Merge "Fix boot loop when deriving device name." into lmp-dev
diff --git a/core/java/android/animation/PathKeyframes.java b/core/java/android/animation/PathKeyframes.java
index 70eed90..2a47b68 100644
--- a/core/java/android/animation/PathKeyframes.java
+++ b/core/java/android/animation/PathKeyframes.java
@@ -17,7 +17,6 @@
import android.graphics.Path;
import android.graphics.PointF;
-import android.util.MathUtils;
import java.util.ArrayList;
@@ -64,11 +63,12 @@
@Override
public Object getValue(float fraction) {
- fraction = MathUtils.constrain(fraction, 0, 1);
-
int numPoints = mKeyframeData.length / 3;
-
- if (fraction == 0) {
+ if (fraction < 0) {
+ return interpolateInRange(fraction, 0, 1);
+ } else if (fraction > 1) {
+ return interpolateInRange(fraction, numPoints - 2, numPoints - 1);
+ } else if (fraction == 0) {
return pointForIndex(0);
} else if (fraction == 1) {
return pointForIndex(numPoints - 1);
@@ -91,27 +91,31 @@
}
// now high is below the fraction and low is above the fraction
- int startBase = (high * NUM_COMPONENTS);
- int endBase = (low * NUM_COMPONENTS);
-
- float startFraction = mKeyframeData[startBase + FRACTION_OFFSET];
- float endFraction = mKeyframeData[endBase + FRACTION_OFFSET];
-
- float intervalFraction = (fraction - startFraction)/(endFraction - startFraction);
-
- float startX = mKeyframeData[startBase + X_OFFSET];
- float endX = mKeyframeData[endBase + X_OFFSET];
- float startY = mKeyframeData[startBase + Y_OFFSET];
- float endY = mKeyframeData[endBase + Y_OFFSET];
-
- float x = interpolate(intervalFraction, startX, endX);
- float y = interpolate(intervalFraction, startY, endY);
-
- mTempPointF.set(x, y);
- return mTempPointF;
+ return interpolateInRange(fraction, high, low);
}
}
+ private PointF interpolateInRange(float fraction, int startIndex, int endIndex) {
+ int startBase = (startIndex * NUM_COMPONENTS);
+ int endBase = (endIndex * NUM_COMPONENTS);
+
+ float startFraction = mKeyframeData[startBase + FRACTION_OFFSET];
+ float endFraction = mKeyframeData[endBase + FRACTION_OFFSET];
+
+ float intervalFraction = (fraction - startFraction)/(endFraction - startFraction);
+
+ float startX = mKeyframeData[startBase + X_OFFSET];
+ float endX = mKeyframeData[endBase + X_OFFSET];
+ float startY = mKeyframeData[startBase + Y_OFFSET];
+ float endY = mKeyframeData[endBase + Y_OFFSET];
+
+ float x = interpolate(intervalFraction, startX, endX);
+ float y = interpolate(intervalFraction, startY, endY);
+
+ mTempPointF.set(x, y);
+ return mTempPointF;
+ }
+
@Override
public void invalidateCache() {
}
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index 43fa3f0..d02d17f 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -223,7 +223,10 @@
mSharedElementNames.addAll(sharedElements.keySet());
mSharedElements.addAll(sharedElements.values());
if (getViewsTransition() != null) {
- getDecor().captureTransitioningViews(mTransitioningViews);
+ ViewGroup decorView = getDecor();
+ if (decorView != null) {
+ decorView.captureTransitioningViews(mTransitioningViews);
+ }
mTransitioningViews.removeAll(mSharedElements);
}
setEpicenter();
@@ -235,6 +238,7 @@
View view = mTransitioningViews.get(i);
if (!view.getGlobalVisibleRect(r)) {
mTransitioningViews.remove(i);
+ showView(view, true);
}
}
}
@@ -350,7 +354,10 @@
sharedElements.put(accepted.get(i), localViews.get(i));
}
} else {
- getDecor().findNamedViews(sharedElements);
+ ViewGroup decorView = getDecor();
+ if (decorView != null) {
+ decorView.findNamedViews(sharedElements);
+ }
}
return sharedElements;
}
@@ -471,16 +478,18 @@
protected void scheduleSetSharedElementEnd(final ArrayList<View> snapshots) {
final View decorView = getDecor();
- decorView.getViewTreeObserver().addOnPreDrawListener(
- new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- decorView.getViewTreeObserver().removeOnPreDrawListener(this);
- notifySharedElementEnd(snapshots);
- return true;
+ if (decorView != null) {
+ decorView.getViewTreeObserver().addOnPreDrawListener(
+ new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ decorView.getViewTreeObserver().removeOnPreDrawListener(this);
+ notifySharedElementEnd(snapshots);
+ return true;
+ }
}
- }
- );
+ );
+ }
}
private static SharedElementOriginalState getOldSharedElementState(View view, String name,
@@ -523,7 +532,10 @@
ArrayList<View> snapshots = new ArrayList<View>(numSharedElements);
Context context = getWindow().getContext();
int[] decorLoc = new int[2];
- getDecor().getLocationOnScreen(decorLoc);
+ ViewGroup decorView = getDecor();
+ if (decorView != null) {
+ decorView.getLocationOnScreen(decorLoc);
+ }
for (String name: names) {
Bundle sharedElementBundle = state.getBundle(name);
if (sharedElementBundle != null) {
@@ -605,14 +617,17 @@
protected void showViews(ArrayList<View> views, boolean setTransitionAlpha) {
int count = views.size();
for (int i = 0; i < count; i++) {
- View view = views.get(i);
- Float alpha = mOriginalAlphas.remove(view);
- if (alpha != null) {
- view.setAlpha(alpha);
- }
- if (setTransitionAlpha) {
- view.setTransitionAlpha(1f);
- }
+ showView(views.get(i), setTransitionAlpha);
+ }
+ }
+
+ private void showView(View view, boolean setTransitionAlpha) {
+ Float alpha = mOriginalAlphas.remove(view);
+ if (alpha != null) {
+ view.setAlpha(alpha);
+ }
+ if (setTransitionAlpha) {
+ view.setTransitionAlpha(1f);
}
}
@@ -746,15 +761,17 @@
protected void scheduleGhostVisibilityChange(final int visibility) {
final View decorView = getDecor();
- decorView.getViewTreeObserver()
- .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- decorView.getViewTreeObserver().removeOnPreDrawListener(this);
- setGhostVisibility(visibility);
- return true;
- }
- });
+ if (decorView != null) {
+ decorView.getViewTreeObserver()
+ .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ decorView.getViewTreeObserver().removeOnPreDrawListener(this);
+ setGhostVisibility(visibility);
+ return true;
+ }
+ });
+ }
}
protected class ContinueTransitionListener extends Transition.TransitionListenerAdapter {
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index 9ca150d..bfdb0eb 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -70,16 +70,18 @@
resultReceiverBundle.putParcelable(KEY_REMOTE_RECEIVER, this);
mResultReceiver.send(MSG_SET_REMOTE_RECEIVER, resultReceiverBundle);
final View decorView = getDecor();
- decorView.getViewTreeObserver().addOnPreDrawListener(
- new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- if (mIsReadyForTransition) {
- decorView.getViewTreeObserver().removeOnPreDrawListener(this);
+ if (decorView != null) {
+ decorView.getViewTreeObserver().addOnPreDrawListener(
+ new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ if (mIsReadyForTransition) {
+ decorView.getViewTreeObserver().removeOnPreDrawListener(this);
+ }
+ return mIsReadyForTransition;
}
- return mIsReadyForTransition;
- }
- });
+ });
+ }
}
public void viewInstancesReady(ArrayList<String> accepted, ArrayList<String> localNames,
@@ -152,7 +154,10 @@
private ArrayMap<String, View> mapNamedElements(ArrayList<String> accepted,
ArrayList<String> localNames) {
ArrayMap<String, View> sharedElements = new ArrayMap<String, View>();
- getDecor().findNamedViews(sharedElements);
+ ViewGroup decorView = getDecor();
+ if (decorView != null) {
+ decorView.findNamedViews(sharedElements);
+ }
if (accepted != null) {
for (int i = 0; i < localNames.size(); i++) {
String localName = localNames.get(i);
@@ -170,10 +175,13 @@
private void sendSharedElementDestination() {
boolean allReady;
+ final View decorView = getDecor();
if (allowOverlappingTransitions() && getEnterViewsTransition() != null) {
allReady = false;
+ } else if (decorView == null) {
+ allReady = true;
} else {
- allReady = !getDecor().isLayoutRequested();
+ allReady = !decorView.isLayoutRequested();
if (allReady) {
for (int i = 0; i < mSharedElements.size(); i++) {
if (mSharedElements.get(i).isLayoutRequested()) {
@@ -188,8 +196,7 @@
setSharedElementMatrices();
moveSharedElementsToOverlay();
mResultReceiver.send(MSG_SHARED_ELEMENT_DESTINATION, state);
- } else {
- final View decorView = getDecor();
+ } else if (decorView != null) {
decorView.getViewTreeObserver()
.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
@@ -291,6 +298,10 @@
}
private void startSharedElementTransition(Bundle sharedElementState) {
+ ViewGroup decorView = getDecor();
+ if (decorView == null) {
+ return;
+ }
// Remove rejected shared elements
ArrayList<String> rejectedNames = new ArrayList<String>(mAllSharedElementNames);
rejectedNames.removeAll(mSharedElementNames);
@@ -311,7 +322,8 @@
boolean startSharedElementTransition = true;
setGhostVisibility(View.INVISIBLE);
scheduleGhostVisibilityChange(View.INVISIBLE);
- Transition transition = beginTransition(startEnterTransition, startSharedElementTransition);
+ Transition transition = beginTransition(decorView, startEnterTransition,
+ startSharedElementTransition);
scheduleGhostVisibilityChange(View.VISIBLE);
setGhostVisibility(View.VISIBLE);
@@ -324,8 +336,9 @@
if (mResultReceiver != null) {
// We can't trust that the view will disappear on the same frame that the shared
// element appears here. Assure that we get at least 2 frames for double-buffering.
- getDecor().postOnAnimation(new Runnable() {
+ decorView.postOnAnimation(new Runnable() {
int mAnimations;
+
@Override
public void run() {
if (mAnimations++ < MIN_ANIMATION_FRAMES) {
@@ -349,21 +362,23 @@
final Bundle sharedElementState = mSharedElementsBundle;
mSharedElementsBundle = null;
final View decorView = getDecor();
- decorView.getViewTreeObserver()
- .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- decorView.getViewTreeObserver().removeOnPreDrawListener(this);
- startTransition(new Runnable() {
- @Override
- public void run() {
- startSharedElementTransition(sharedElementState);
- }
- });
- return false;
- }
- });
- decorView.invalidate();
+ if (decorView != null) {
+ decorView.getViewTreeObserver()
+ .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ decorView.getViewTreeObserver().removeOnPreDrawListener(this);
+ startTransition(new Runnable() {
+ @Override
+ public void run() {
+ startSharedElementTransition(sharedElementState);
+ }
+ });
+ return false;
+ }
+ });
+ decorView.invalidate();
+ }
}
private void requestLayoutForSharedElements() {
@@ -373,7 +388,7 @@
}
}
- private Transition beginTransition(boolean startEnterTransition,
+ private Transition beginTransition(ViewGroup decorView, boolean startEnterTransition,
boolean startSharedElementTransition) {
Transition sharedElementTransition = null;
if (startSharedElementTransition) {
@@ -433,7 +448,7 @@
Transition transition = mergeTransitions(sharedElementTransition, viewsTransition);
if (transition != null) {
transition.addListener(new ContinueTransitionListener());
- TransitionManager.beginDelayedTransition(getDecor(), transition);
+ TransitionManager.beginDelayedTransition(decorView, transition);
if (startSharedElementTransition && !mSharedElementNames.isEmpty()) {
mSharedElements.get(0).invalidate();
} else if (startEnterTransition && !mTransitioningViews.isEmpty()) {
@@ -467,8 +482,9 @@
}
private void startEnterTransition(Transition transition) {
- if (!mIsReturning) {
- Drawable background = getDecor().getBackground();
+ ViewGroup decorView = getDecor();
+ if (!mIsReturning && decorView != null) {
+ Drawable background = decorView.getBackground();
if (background != null) {
background = background.mutate();
getWindow().setBackgroundDrawable(background);
@@ -539,25 +555,28 @@
if (rejectedSnapshots == null || rejectedSnapshots.isEmpty()) {
return;
}
- ViewGroupOverlay overlay = getDecor().getOverlay();
- ObjectAnimator animator = null;
- int numRejected = rejectedSnapshots.size();
- for (int i = 0; i < numRejected; i++) {
- View snapshot = rejectedSnapshots.get(i);
- overlay.add(snapshot);
- animator = ObjectAnimator.ofFloat(snapshot, View.ALPHA, 1, 0);
- animator.start();
- }
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- ViewGroupOverlay overlay = getDecor().getOverlay();
- int numRejected = rejectedSnapshots.size();
- for (int i = 0; i < numRejected; i++) {
- overlay.remove(rejectedSnapshots.get(i));
- }
+ final ViewGroup decorView = getDecor();
+ if (decorView != null) {
+ ViewGroupOverlay overlay = decorView.getOverlay();
+ ObjectAnimator animator = null;
+ int numRejected = rejectedSnapshots.size();
+ for (int i = 0; i < numRejected; i++) {
+ View snapshot = rejectedSnapshots.get(i);
+ overlay.add(snapshot);
+ animator = ObjectAnimator.ofFloat(snapshot, View.ALPHA, 1, 0);
+ animator.start();
}
- });
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ ViewGroupOverlay overlay = decorView.getOverlay();
+ int numRejected = rejectedSnapshots.size();
+ for (int i = 0; i < numRejected; i++) {
+ overlay.remove(rejectedSnapshots.get(i));
+ }
+ }
+ });
+ }
}
protected void onRemoteExitTransitionComplete() {
@@ -572,9 +591,12 @@
public void run() {
boolean startEnterTransition = true;
boolean startSharedElementTransition = false;
- Transition transition = beginTransition(startEnterTransition,
- startSharedElementTransition);
- startEnterTransition(transition);
+ ViewGroup decorView = getDecor();
+ if (decorView != null) {
+ Transition transition = beginTransition(decorView, startEnterTransition,
+ startSharedElementTransition);
+ startEnterTransition(transition);
+ }
}
});
}
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index e85ec63..41b0db6 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -129,22 +129,25 @@
showViews(mTransitioningViews, true);
showViews(mSharedElements, true);
mIsHidden = true;
- if (!mIsReturning && getDecor() != null) {
- getDecor().suppressLayout(false);
+ ViewGroup decorView = getDecor();
+ if (!mIsReturning && decorView != null) {
+ decorView.suppressLayout(false);
}
moveSharedElementsFromOverlay();
clearState();
}
private void sharedElementExitBack() {
- if (getDecor() != null) {
- getDecor().suppressLayout(true);
+ final ViewGroup decorView = getDecor();
+ if (decorView != null) {
+ decorView.suppressLayout(true);
}
- if (mExitSharedElementBundle != null && !mExitSharedElementBundle.isEmpty() &&
+ if (decorView != null && mExitSharedElementBundle != null &&
+ !mExitSharedElementBundle.isEmpty() &&
!mSharedElements.isEmpty() && getSharedElementTransition() != null) {
startTransition(new Runnable() {
public void run() {
- startSharedElementExit();
+ startSharedElementExit(decorView);
}
});
} else {
@@ -152,7 +155,7 @@
}
}
- private void startSharedElementExit() {
+ private void startSharedElementExit(final ViewGroup decorView) {
Transition transition = getSharedElementExitTransition();
transition.addListener(new Transition.TransitionListenerAdapter() {
@Override
@@ -165,7 +168,6 @@
});
final ArrayList<View> sharedElementSnapshots = createSnapshots(mExitSharedElementBundle,
mSharedElementNames);
- final View decorView = getDecor();
decorView.getViewTreeObserver()
.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
@@ -178,10 +180,10 @@
setGhostVisibility(View.INVISIBLE);
scheduleGhostVisibilityChange(View.INVISIBLE);
mListener.onSharedElementEnd(mSharedElementNames, mSharedElements, sharedElementSnapshots);
- TransitionManager.beginDelayedTransition(getDecor(), transition);
+ TransitionManager.beginDelayedTransition(decorView, transition);
scheduleGhostVisibilityChange(View.VISIBLE);
setGhostVisibility(View.VISIBLE);
- getDecor().invalidate();
+ decorView.invalidate();
}
private void hideSharedElements() {
@@ -196,8 +198,9 @@
public void startExit() {
if (!mIsExitStarted) {
mIsExitStarted = true;
- if (getDecor() != null) {
- getDecor().suppressLayout(true);
+ ViewGroup decorView = getDecor();
+ if (decorView != null) {
+ decorView.suppressLayout(true);
}
moveSharedElementsToOverlay();
startTransition(new Runnable() {
@@ -212,8 +215,9 @@
public void startExit(int resultCode, Intent data) {
if (!mIsExitStarted) {
mIsExitStarted = true;
- if (getDecor() != null) {
- getDecor().suppressLayout(true);
+ ViewGroup decorView = getDecor();
+ if (decorView != null) {
+ decorView.suppressLayout(true);
}
mHandler = new Handler() {
@Override
@@ -224,7 +228,7 @@
};
delayCancel();
moveSharedElementsToOverlay();
- if (getDecor().getBackground() == null) {
+ if (decorView != null && decorView.getBackground() == null) {
getWindow().setBackgroundDrawable(new ColorDrawable(Color.BLACK));
}
ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(mActivity, this,
@@ -248,8 +252,9 @@
private void startExitTransition() {
Transition transition = getExitTransition();
- if (transition != null) {
- TransitionManager.beginDelayedTransition(getDecor(), transition);
+ ViewGroup decorView = getDecor();
+ if (transition != null && decorView != null) {
+ TransitionManager.beginDelayedTransition(decorView, transition);
mTransitioningViews.get(0).invalidate();
} else {
transitionStarted();
@@ -337,13 +342,14 @@
Transition viewsTransition = getExitTransition();
Transition transition = mergeTransitions(sharedElementTransition, viewsTransition);
- if (transition != null) {
+ ViewGroup decorView = getDecor();
+ if (transition != null && decorView != null) {
setGhostVisibility(View.INVISIBLE);
scheduleGhostVisibilityChange(View.INVISIBLE);
- TransitionManager.beginDelayedTransition(getDecor(), transition);
+ TransitionManager.beginDelayedTransition(decorView, transition);
scheduleGhostVisibilityChange(View.VISIBLE);
setGhostVisibility(View.VISIBLE);
- getDecor().invalidate();
+ decorView.invalidate();
} else {
transitionStarted();
}
@@ -392,8 +398,9 @@
mExitNotified = true;
mResultReceiver.send(MSG_EXIT_TRANSITION_COMPLETE, null);
mResultReceiver = null; // done talking
- if (!mIsReturning && getDecor() != null) {
- getDecor().suppressLayout(false);
+ ViewGroup decorView = getDecor();
+ if (!mIsReturning && decorView != null) {
+ decorView.suppressLayout(false);
}
finishIfNecessary();
}
diff --git a/core/java/android/hardware/camera2/params/TonemapCurve.java b/core/java/android/hardware/camera2/params/TonemapCurve.java
index 481d67a..398a7e9 100644
--- a/core/java/android/hardware/camera2/params/TonemapCurve.java
+++ b/core/java/android/hardware/camera2/params/TonemapCurve.java
@@ -81,7 +81,8 @@
* <p>Values are stored as a contiguous array of {@code (Pin, Pout)} points.</p>
*
* <p>All parameters may have independent length but should have at most
- * {@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS} * {@value #POINT_SIZE} elements.</p>
+ * {@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS} * {@value #POINT_SIZE} elements and
+ * at least 2 * {@value #POINT_SIZE} elements.</p>
*
* <p>All sub-elements must be in the inclusive range of
* [{@value #LEVEL_BLACK}, {@value #LEVEL_WHITE}].</p>
@@ -110,6 +111,10 @@
checkArgumentArrayLengthDivisibleBy(green, POINT_SIZE, "green");
checkArgumentArrayLengthDivisibleBy(blue, POINT_SIZE, "blue");
+ checkArgumentArrayLengthNoLessThan(red, MIN_CURVE_LENGTH, "red");
+ checkArgumentArrayLengthNoLessThan(green, MIN_CURVE_LENGTH, "green");
+ checkArgumentArrayLengthNoLessThan(blue, MIN_CURVE_LENGTH, "blue");
+
checkArrayElementsInRange(red, LEVEL_BLACK, LEVEL_WHITE, "red");
checkArrayElementsInRange(green, LEVEL_BLACK, LEVEL_WHITE, "green");
checkArrayElementsInRange(blue, LEVEL_BLACK, LEVEL_WHITE, "blue");
@@ -140,6 +145,14 @@
return colorChannel;
}
+ private static void checkArgumentArrayLengthNoLessThan(float[] array, int minLength,
+ String arrayName) {
+ if (array.length < minLength) {
+ throw new IllegalArgumentException(arrayName + " size must be at least "
+ + minLength);
+ }
+ }
+
/**
* Get the number of points stored in this tonemap curve for the specified color channel.
*
@@ -270,6 +283,47 @@
return mHashCode;
}
+ /**
+ * Return the TonemapCurve as a string representation.
+ *
+ * <p> {@code "TonemapCurve{R:[(%f, %f), (%f, %f) ... (%f, %f)], G:[(%f, %f), (%f, %f) ...
+ * (%f, %f)], B:[(%f, %f), (%f, %f) ... (%f, %f)]}"},
+ * where each {@code (%f, %f)} respectively represents one point of the corresponding
+ * tonemap curve. </p>
+ *
+ * @return string representation of {@link TonemapCurve}
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("TonemapCurve{");
+ sb.append("R:");
+ sb.append(curveToString(CHANNEL_RED));
+ sb.append(", G:");
+ sb.append(curveToString(CHANNEL_GREEN));
+ sb.append(", B:");
+ sb.append(curveToString(CHANNEL_BLUE));
+ sb.append("}");
+ return sb.toString();
+ }
+
+ private String curveToString(int colorChannel) {
+ checkArgumentColorChannel(colorChannel);
+ StringBuilder sb = new StringBuilder("[");
+ float[] curve = getCurve(colorChannel);
+ int pointCount = curve.length / POINT_SIZE;
+ for (int i = 0, j = 0; i < pointCount; i++, j += 2) {
+ sb.append("(");
+ sb.append(curve[j]);
+ sb.append(", ");
+ sb.append(curve[j+1]);
+ sb.append("), ");
+ }
+ // trim extra ", " at the end. Guaranteed to work because pointCount >= 2
+ sb.setLength(sb.length() - 2);
+ sb.append("]");
+ return sb.toString();
+ }
+
private float[] getCurve(int colorChannel) {
switch (colorChannel) {
case CHANNEL_RED:
@@ -285,6 +339,8 @@
private final static int OFFSET_POINT_IN = 0;
private final static int OFFSET_POINT_OUT = 1;
+ private final static int TONEMAP_MIN_CURVE_POINTS = 2;
+ private final static int MIN_CURVE_LENGTH = TONEMAP_MIN_CURVE_POINTS * POINT_SIZE;
private final float[] mRed;
private final float[] mGreen;
@@ -292,4 +348,4 @@
private int mHashCode;
private boolean mHashCalculated = false;
-};
+}
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index d1ad0ad..5230128 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -236,6 +236,7 @@
private static final int EX_NULL_POINTER = -4;
private static final int EX_ILLEGAL_STATE = -5;
private static final int EX_NETWORK_MAIN_THREAD = -6;
+ private static final int EX_UNSUPPORTED_OPERATION = -7;
private static final int EX_HAS_REPLY_HEADER = -128; // special; see below
private static native int nativeDataSize(long nativePtr);
@@ -1427,6 +1428,8 @@
code = EX_ILLEGAL_STATE;
} else if (e instanceof NetworkOnMainThreadException) {
code = EX_NETWORK_MAIN_THREAD;
+ } else if (e instanceof UnsupportedOperationException) {
+ code = EX_UNSUPPORTED_OPERATION;
}
writeInt(code);
StrictMode.clearGatheredViolations();
@@ -1545,6 +1548,8 @@
throw new IllegalStateException(msg);
case EX_NETWORK_MAIN_THREAD:
throw new NetworkOnMainThreadException();
+ case EX_UNSUPPORTED_OPERATION:
+ throw new UnsupportedOperationException(msg);
}
throw new RuntimeException("Unknown exception code: " + code
+ " msg " + msg);
diff --git a/core/res/res/layout/action_mode_close_item_material.xml b/core/res/res/layout/action_mode_close_item_material.xml
index 8eb780b..89a1797 100644
--- a/core/res/res/layout/action_mode_close_item_material.xml
+++ b/core/res/res/layout/action_mode_close_item_material.xml
@@ -20,6 +20,7 @@
android:clickable="true"
android:paddingStart="8dip"
android:src="?android:attr/actionModeCloseDrawable"
+ android:contentDescription="@string/action_mode_done"
style="?android:attr/actionModeCloseButtonStyle"
android:layout_width="wrap_content"
android:layout_height="match_parent"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 438d1fb..0e597d0 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -5271,11 +5271,16 @@
<attr name="viewportWidth" format="float"/>
<!-- The height of the canvas the drawing is on. -->
<attr name="viewportHeight" format="float"/>
+ <!-- The name of this vector drawable -->
+ <attr name="name" />
+ <!-- The opacity of the whole vector drawable, as a value between 0
+ (completely transparent) and 1 (completely opaque). -->
+ <attr name="alpha" />
</declare-styleable>
<!-- Defines the group used in VectorDrawables. -->
<declare-styleable name="VectorDrawableGroup">
- <!-- The Name of this group -->
+ <!-- The name of this group -->
<attr name="name" />
<!-- The amount to rotate the group -->
<attr name="rotation" />
@@ -5295,7 +5300,7 @@
<!-- Defines the path used in VectorDrawables. -->
<declare-styleable name="VectorDrawablePath">
- <!-- The Name of this path -->
+ <!-- The name of this path -->
<attr name="name" />
<!-- The width a path stroke -->
<attr name="strokeWidth" format="float" />
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 62eb4c8..dd87699 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -256,21 +256,22 @@
}
if (!mAllowCaching) {
- mVectorState.mVPathRenderer.draw(canvas, bounds.width(), bounds.height());
+ // AnimatedVectorDrawable
+ if (!mVectorState.hasTranslucentRoot()) {
+ mVectorState.mVPathRenderer.draw(canvas, bounds.width(), bounds.height());
+ } else {
+ mVectorState.createCachedBitmapIfNeeded(bounds);
+ mVectorState.updateCachedBitmap(bounds);
+ mVectorState.drawCachedBitmapWithRootAlpha(canvas);
+ }
} else {
- Bitmap bitmap = mVectorState.mCachedBitmap;
- if (bitmap == null || !mVectorState.canReuseCache(bounds.width(),
- bounds.height())) {
- bitmap = Bitmap.createBitmap(bounds.width(), bounds.height(),
- Bitmap.Config.ARGB_8888);
- Canvas tmpCanvas = new Canvas(bitmap);
- mVectorState.mVPathRenderer.draw(tmpCanvas, bounds.width(), bounds.height());
- mVectorState.mCachedBitmap = bitmap;
-
+ // Static Vector Drawable case.
+ mVectorState.createCachedBitmapIfNeeded(bounds);
+ if (!mVectorState.canReuseCache()) {
+ mVectorState.updateCachedBitmap(bounds);
mVectorState.updateCacheStates();
}
- // The bitmap's size is the same as the bounds.
- canvas.drawBitmap(bitmap, 0, 0, null);
+ mVectorState.drawCachedBitmapWithRootAlpha(canvas);
}
canvas.restoreToCount(saveCount);
@@ -514,6 +515,15 @@
throw new XmlPullParserException(a.getPositionDescription() +
"<vector> tag requires height > 0");
}
+
+ final float alphaInFloat = a.getFloat(R.styleable.VectorDrawable_alpha,
+ pathRenderer.getAlpha());
+ pathRenderer.setAlpha(alphaInFloat);
+
+ pathRenderer.mRootName = a.getString(R.styleable.VectorDrawable_name);
+ if (pathRenderer.mRootName != null) {
+ pathRenderer.mVGTargetsMap.put(pathRenderer.mRootName, pathRenderer);
+ }
}
private void inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs,
@@ -668,15 +678,60 @@
}
}
- public boolean canReuseCache(int width, int height) {
+ // TODO: Support colorFilter here.
+ public void drawCachedBitmapWithRootAlpha(Canvas canvas) {
+ Paint alphaPaint = getRootAlphaPaint();
+ // The bitmap's size is the same as the bounds.
+ canvas.drawBitmap(mCachedBitmap, 0, 0, alphaPaint);
+ }
+
+ public boolean hasTranslucentRoot() {
+ return mVPathRenderer.getRootAlpha() < 255;
+ }
+
+ /**
+ * @return null when there is no need for alpha paint.
+ */
+ public Paint getRootAlphaPaint() {
+ Paint paint = null;
+ boolean needsAlphaPaint = hasTranslucentRoot();
+ if (needsAlphaPaint) {
+ paint = new Paint();
+ paint.setAlpha(mVPathRenderer.getRootAlpha());
+ }
+ return paint;
+ }
+
+ public void updateCachedBitmap(Rect bounds) {
+ mCachedBitmap.eraseColor(Color.TRANSPARENT);
+ Canvas tmpCanvas = new Canvas(mCachedBitmap);
+ mVPathRenderer.draw(tmpCanvas, bounds.width(), bounds.height());
+ }
+
+ public void createCachedBitmapIfNeeded(Rect bounds) {
+ if (mCachedBitmap == null || !canReuseBitmap(bounds.width(),
+ bounds.height())) {
+ mCachedBitmap = Bitmap.createBitmap(bounds.width(), bounds.height(),
+ Bitmap.Config.ARGB_8888);
+ }
+
+ }
+
+ public boolean canReuseBitmap(int width, int height) {
+ if (width == mCachedBitmap.getWidth()
+ && height == mCachedBitmap.getHeight()) {
+ return true;
+ }
+ return false;
+ }
+
+ public boolean canReuseCache() {
if (!mCacheDirty
&& mCachedThemeAttrs == mThemeAttrs
&& mCachedTint == mTint
&& mCachedTintMode == mTintMode
&& mCachedAutoMirrored == mAutoMirrored
- && width == mCachedBitmap.getWidth()
- && height == mCachedBitmap.getHeight()
- && mCachedRootAlpha == mVPathRenderer.getRootAlpha()) {
+ && mCachedRootAlpha == mVPathRenderer.getRootAlpha()) {
return true;
}
return false;
@@ -763,7 +818,8 @@
float mBaseHeight = 0;
float mViewportWidth = 0;
float mViewportHeight = 0;
- private int mRootAlpha = 0xFF;
+ int mRootAlpha = 0xFF;
+ String mRootName = null;
final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<String, Object>();
@@ -781,6 +837,17 @@
return mRootAlpha;
}
+ // setAlpha() and getAlpha() are used mostly for animation purpose, since
+ // Animator like to use alpha from 0 to 1.
+ public void setAlpha(float alpha) {
+ setRootAlpha((int) (alpha * 255));
+ }
+
+ @SuppressWarnings("unused")
+ public float getAlpha() {
+ return getRootAlpha() / 255.0f;
+ }
+
public VPathRenderer(VPathRenderer copy) {
mRootGroup = new VGroup(copy.mRootGroup, mVGTargetsMap);
mPath = new Path(copy.mPath);
@@ -791,6 +858,10 @@
mViewportHeight = copy.mViewportHeight;
mChangingConfigurations = copy.mChangingConfigurations;
mRootAlpha = copy.mRootAlpha;
+ mRootName = copy.mRootName;
+ if (copy.mRootName != null) {
+ mVGTargetsMap.put(copy.mRootName, this);
+ }
}
public boolean canApplyTheme() {
@@ -894,7 +965,7 @@
}
private void drawPath(VGroup vGroup, VPath vPath, Canvas canvas, int w, int h) {
- final float scaleX = w / mViewportWidth;
+ final float scaleX = w / mViewportWidth;
final float scaleY = h / mViewportHeight;
final float minScale = Math.min(scaleX, scaleY);
@@ -1256,7 +1327,7 @@
/**
* Clip path, which only has name and pathData.
*/
- private static class VClipPath extends VPath{
+ private static class VClipPath extends VPath {
public VClipPath() {
// Empty constructor.
}
diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
index e0901d0..f0a2072 100644
--- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
+++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
@@ -34,6 +34,7 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.SystemProperties;
+import android.provider.Settings;
import android.util.Log;
import com.android.internal.R;
@@ -110,6 +111,9 @@
// Set to true if the phone is having emergency call.
private volatile boolean mIsInEmergency;
+ // If Location function is enabled.
+ private volatile boolean mIsLocationEnabled = false;
+
private final INetInitiatedListener mNetInitiatedListener;
// Set to true if string from HAL is encoded as Hex, e.g., "3F0039"
@@ -132,7 +136,7 @@
};
public static class GpsNiResponse {
- /* User reponse, one of the values in GpsUserResponseType */
+ /* User response, one of the values in GpsUserResponseType */
int userResponse;
/* Optional extra data to pass with the user response */
Bundle extras;
@@ -154,8 +158,11 @@
Emergency call back mode will be checked by reading system properties
when necessary: SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE)
*/
- mIsInEmergency |= PhoneNumberUtils.isEmergencyNumber(phoneNumber);
- if (DEBUG) Log.v(TAG, "ACTION_NEW_OUTGOING_CALL - " + mIsInEmergency);
+ setInEmergency(PhoneNumberUtils.isEmergencyNumber(phoneNumber));
+ if (DEBUG) Log.v(TAG, "ACTION_NEW_OUTGOING_CALL - " + getInEmergency());
+ } else if (action.equals(LocationManager.MODE_CHANGED_ACTION)) {
+ updateLocationMode();
+ if (DEBUG) Log.d(TAG, "location enabled :" + getLocationEnabled());
}
}
};
@@ -179,8 +186,9 @@
mNetInitiatedListener = netInitiatedListener;
}
- mIsSuplEsEnabled = isSuplEsEnabled;
+ setSuplEsEnabled(isSuplEsEnabled);
mLocationManager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
+ updateLocationMode();
mTelephonyManager =
(TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
@@ -190,7 +198,7 @@
if (DEBUG) Log.d(TAG, "onCallStateChanged(): state is "+ state);
// listening for emergency call ends
if (state == TelephonyManager.CALL_STATE_IDLE) {
- mIsInEmergency = false;
+ setInEmergency(false);
}
}
};
@@ -198,27 +206,65 @@
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_NEW_OUTGOING_CALL);
+ intentFilter.addAction(LocationManager.MODE_CHANGED_ACTION);
mContext.registerReceiver(mBroadcastReciever, intentFilter);
}
- public void setSuplEsEnablement(boolean isEnabled)
- {
+ public void setSuplEsEnabled(boolean isEnabled) {
mIsSuplEsEnabled = isEnabled;
}
+ public boolean getSuplEsEnabled() {
+ return mIsSuplEsEnabled;
+ }
+
+ /**
+ * Updates Location enabler based on location setting.
+ */
+ public void updateLocationMode() {
+ mIsLocationEnabled = mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
+ }
+
+ /**
+ * Checks if user agreed to use location.
+ */
+ public boolean getLocationEnabled() {
+ return mIsLocationEnabled;
+ }
+
+ // Note: Currently, there are two mechanisms involved to determine if a
+ // phone is in emergency mode:
+ // 1. If the user is making an emergency call, this is provided by activly
+ // monitoring the outgoing phone number;
+ // 2. If the device is in a emergency callback state, this is provided by
+ // system properties.
+ // If either one of above exists, the phone is considered in an emergency
+ // mode. Because of this complexity, we need to be careful about how to set
+ // and clear the emergency state.
+ public void setInEmergency(boolean isInEmergency) {
+ mIsInEmergency = isInEmergency;
+ }
+
+ public boolean getInEmergency() {
+ boolean isInEmergencyCallback = Boolean.parseBoolean(
+ SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE));
+ return mIsInEmergency || isInEmergencyCallback;
+ }
+
+
// Handles NI events from HAL
- public void handleNiNotification(GpsNiNotification notif)
- {
+ public void handleNiNotification(GpsNiNotification notif) {
if (DEBUG) Log.d(TAG, "in handleNiNotification () :"
+ " notificationId: " + notif.notificationId
+ " requestorId: " + notif.requestorId
+ " text: " + notif.text
- + " mIsSuplEsEnabled" + mIsSuplEsEnabled);
+ + " mIsSuplEsEnabled" + getSuplEsEnabled()
+ + " mIsLocationEnabled" + getLocationEnabled());
- if (mIsSuplEsEnabled == false) {
- handleNi(notif);
- } else {
+ if (getSuplEsEnabled()) {
handleNiInEs(notif);
+ } else {
+ handleNi(notif);
}
//////////////////////////////////////////////////////////////////////////
@@ -240,9 +286,18 @@
+ " needNotify: " + notif.needNotify
+ " needVerify: " + notif.needVerify
+ " privacyOverride: " + notif.privacyOverride
- + " mPopupImmediately: " + mPopupImmediately);
+ + " mPopupImmediately: " + mPopupImmediately
+ + " mInEmergency: " + getInEmergency());
- // legacy behaviour
+ if (getLocationEnabled() && !getInEmergency()) {
+ // Location is currently disabled, ignore all NI requests.
+ try {
+ mNetInitiatedListener.sendNiResponse(notif.notificationId,
+ GPS_NI_RESPONSE_IGNORE);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in sendNiResponse");
+ }
+ }
if (notif.needNotify) {
// If NI does not need verify or the dialog is not requested
// to pop up immediately, the dialog box will not pop up.
@@ -274,9 +329,6 @@
+ " notificationId: " + notif.notificationId);
// UE is in emergency mode when in emergency call mode or in emergency call back mode
- boolean isUEInEmergencyMode = mIsInEmergency ||
- Boolean.parseBoolean(SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE));
-
/*
1. When SUPL ES bit is off and UE is not in emergency mode:
Call handleNi() to do legacy behaviour.
@@ -288,7 +340,7 @@
Ignore the emergency SUPL INIT.
*/
boolean isNiTypeES = (notif.niType == GPS_NI_TYPE_EMERGENCY_SUPL);
- if (isNiTypeES != isUEInEmergencyMode) {
+ if (isNiTypeES != getInEmergency()) {
try {
mNetInitiatedListener.sendNiResponse(notif.notificationId,
GPS_NI_RESPONSE_IGNORE);
diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml
index adff596..c7cf61a 100644
--- a/packages/PrintSpooler/AndroidManifest.xml
+++ b/packages/PrintSpooler/AndroidManifest.xml
@@ -55,7 +55,8 @@
<service
android:name=".renderer.PdfManipulationService"
- android:isolatedProcess="true">
+ android:isolatedProcess="true"
+ android:process=":renderer">
</service>
<activity
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
index 239f006..429437d 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
@@ -135,7 +135,7 @@
private final DeathRecipient mDeathRecipient = new DeathRecipient() {
@Override
public void binderDied() {
- mAdapterDeathObserver.onDied();
+ notifyPrintingAppDied();
}
};
@@ -180,7 +180,6 @@
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error calling start()", re);
mState = STATE_FAILED;
- mAdapterDeathObserver.onDied();
}
}
@@ -269,7 +268,6 @@
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error calling finish()", re);
mState = STATE_FAILED;
- mAdapterDeathObserver.onDied();
}
}
@@ -1108,6 +1106,15 @@
}
}
+ private void notifyPrintingAppDied() {
+ new Handler(mLooper).post(new Runnable() {
+ @Override
+ public void run() {
+ mAdapterDeathObserver.onDied();
+ }
+ });
+ }
+
private static final class PrintDocumentAdapterObserver
extends IPrintDocumentAdapterObserver.Stub {
private final WeakReference<RemotePrintDocument> mWeakDocument;
@@ -1120,12 +1127,7 @@
public void onDestroy() {
final RemotePrintDocument document = mWeakDocument.get();
if (document != null) {
- new Handler(document.mLooper).post(new Runnable() {
- @Override
- public void run() {
- document.mAdapterDeathObserver.onDied();
- }
- });
+ document.notifyPrintingAppDied();
}
}
}
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index ef6e07c..c3465d1 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -631,7 +631,7 @@
@Override
public int checkPackage(int uid, String packageName) {
synchronized (this) {
- if (getOpsLocked(uid, packageName, true) != null) {
+ if (getOpsRawLocked(uid, packageName, true) != null) {
return AppOpsManager.MODE_ALLOWED;
} else {
return AppOpsManager.MODE_ERRORED;
@@ -769,6 +769,15 @@
}
private Ops getOpsLocked(int uid, String packageName, boolean edit) {
+ if (uid == 0) {
+ packageName = "root";
+ } else if (uid == Process.SHELL_UID) {
+ packageName = "com.android.shell";
+ }
+ return getOpsRawLocked(uid, packageName, edit);
+ }
+
+ private Ops getOpsRawLocked(int uid, String packageName, boolean edit) {
HashMap<String, Ops> pkgOps = mUidOps.get(uid);
if (pkgOps == null) {
if (!edit) {
@@ -777,11 +786,6 @@
pkgOps = new HashMap<String, Ops>();
mUidOps.put(uid, pkgOps);
}
- if (uid == 0) {
- packageName = "root";
- } else if (uid == Process.SHELL_UID) {
- packageName = "com.android.shell";
- }
Ops ops = pkgOps.get(packageName);
if (ops == null) {
if (!edit) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 75090db..7f104c0 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -251,7 +251,7 @@
private Context mContext;
private int mNetworkPreference;
- private int mActiveDefaultNetwork = -1;
+ private int mActiveDefaultNetwork = TYPE_NONE;
// 0 is full bad, 100 is full good
private int mDefaultInetConditionPublished = 0;
@@ -886,15 +886,6 @@
return getNetworkInfo(mActiveDefaultNetwork, uid);
}
- // only called when the default request is satisfied
- private void updateActiveDefaultNetwork(NetworkAgentInfo nai) {
- if (nai != null) {
- mActiveDefaultNetwork = nai.networkInfo.getType();
- } else {
- mActiveDefaultNetwork = TYPE_NONE;
- }
- }
-
/**
* Find the first Provisioning network.
*
@@ -1936,7 +1927,9 @@
case NetworkMonitor.EVENT_NETWORK_VALIDATED: {
NetworkAgentInfo nai = (NetworkAgentInfo)msg.obj;
if (isLiveNetworkAgent(nai, "EVENT_NETWORK_VALIDATED")) {
- handleConnectionValidated(nai);
+ if (DBG) log("Validated " + nai.name());
+ nai.validated = true;
+ rematchNetworkAndRequests(nai);
}
break;
}
@@ -2057,7 +2050,7 @@
if (nri.isRequest == false) continue;
NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId);
ac.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK,
- (nai != null ? nai.currentScore : 0), 0, nri.request);
+ (nai != null ? nai.getCurrentScore() : 0), 0, nri.request);
}
} else {
loge("Error connecting NetworkFactory");
@@ -2136,7 +2129,7 @@
request.networkCapabilities.satisfiedByNetworkCapabilities(
existing.networkCapabilities) &&
(alternative == null ||
- alternative.currentScore < existing.currentScore)) {
+ alternative.getCurrentScore() < existing.getCurrentScore())) {
alternative = existing;
}
}
@@ -2169,8 +2162,9 @@
for (NetworkAgentInfo network : mNetworkAgentInfos.values()) {
if (DBG) log("handleRegisterNetworkRequest checking " + network.name());
if (newCap.satisfiedByNetworkCapabilities(network.networkCapabilities)) {
- if (DBG) log("apparently satisfied. currentScore=" + network.currentScore);
- if ((bestNetwork == null) || bestNetwork.currentScore < network.currentScore) {
+ if (DBG) log("apparently satisfied. currentScore=" + network.getCurrentScore());
+ if ((bestNetwork == null) ||
+ bestNetwork.getCurrentScore() < network.getCurrentScore()) {
if (!nri.isRequest) {
// Not setting bestNetwork here as a listening NetworkRequest may be
// satisfied by multiple Networks. Instead the request is added to
@@ -2194,7 +2188,7 @@
bestNetwork.addRequest(nri.request);
mNetworkForRequestId.put(nri.request.requestId, bestNetwork);
notifyNetworkCallback(bestNetwork, nri);
- score = bestNetwork.currentScore;
+ score = bestNetwork.getCurrentScore();
if (nri.request.legacyType != TYPE_NONE) {
mLegacyTypeTracker.add(nri.request.legacyType, bestNetwork);
}
@@ -4516,19 +4510,34 @@
updateTcpBufferSizes(newNetwork);
}
- private void handleConnectionValidated(NetworkAgentInfo newNetwork) {
- if (newNetwork == null) {
- loge("Unknown NetworkAgentInfo in handleConnectionValidated");
- return;
- }
- if (newNetwork.validated) return;
- newNetwork.validated = true;
+ // Handles a network appearing or improving its score.
+ //
+ // - Evaluates all current NetworkRequests that can be
+ // satisfied by newNetwork, and reassigns to newNetwork
+ // any such requests for which newNetwork is the best.
+ //
+ // - Tears down any Networks that as a result are no longer
+ // needed. A network is needed if it is the best network for
+ // one or more NetworkRequests, or if it is a VPN.
+ //
+ // - Tears down newNetwork if it is validated but turns out to be
+ // unneeded. Does not tear down newNetwork if it is
+ // unvalidated, because future validation may improve
+ // newNetwork's score enough that it is needed.
+ //
+ // NOTE: This function only adds NetworkRequests that "newNetwork" could satisfy,
+ // it does not remove NetworkRequests that other Networks could better satisfy.
+ // If you need to handle decreases in score, use {@link rematchAllNetworksAndRequests}.
+ // This function should be used when possible instead of {@code rematchAllNetworksAndRequests}
+ // as it performs better by a factor of the number of Networks.
+ private void rematchNetworkAndRequests(NetworkAgentInfo newNetwork) {
boolean keep = newNetwork.isVPN();
boolean isNewDefault = false;
- if (DBG) log("handleConnectionValidated for "+newNetwork.name());
- // check if any NetworkRequest wants this NetworkAgent
+ if (DBG) log("rematching " + newNetwork.name());
+ // Find and migrate to this Network any NetworkRequests for
+ // which this network is now the best.
ArrayList<NetworkAgentInfo> affectedNetworks = new ArrayList<NetworkAgentInfo>();
- if (VDBG) log(" new Network has: " + newNetwork.networkCapabilities);
+ if (VDBG) log(" network has: " + newNetwork.networkCapabilities);
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId);
if (newNetwork == currentNetwork) {
@@ -4543,18 +4552,21 @@
if (nri.request.networkCapabilities.satisfiedByNetworkCapabilities(
newNetwork.networkCapabilities)) {
if (!nri.isRequest) {
+ // This is not a request, it's a callback listener.
+ // Add it to newNetwork regardless of score.
newNetwork.addRequest(nri.request);
continue;
}
+
// next check if it's better than any current network we're using for
// this request
if (VDBG) {
log("currentScore = " +
- (currentNetwork != null ? currentNetwork.currentScore : 0) +
- ", newScore = " + newNetwork.currentScore);
+ (currentNetwork != null ? currentNetwork.getCurrentScore() : 0) +
+ ", newScore = " + newNetwork.getCurrentScore());
}
if (currentNetwork == null ||
- currentNetwork.currentScore < newNetwork.currentScore) {
+ currentNetwork.getCurrentScore() < newNetwork.getCurrentScore()) {
if (currentNetwork != null) {
if (DBG) log(" accepting network in place of " + currentNetwork.name());
currentNetwork.networkRequests.remove(nri.request.requestId);
@@ -4569,13 +4581,16 @@
mLegacyTypeTracker.add(nri.request.legacyType, newNetwork);
}
keep = true;
+ // Tell NetworkFactories about the new score, so they can stop
+ // trying to connect if they know they cannot match it.
// TODO - this could get expensive if we have alot of requests for this
// network. Think about if there is a way to reduce this. Push
// netid->request mapping to each factory?
- sendUpdatedScoreToFactories(nri.request, newNetwork.currentScore);
+ sendUpdatedScoreToFactories(nri.request, newNetwork.getCurrentScore());
if (mDefaultRequest.requestId == nri.request.requestId) {
isNewDefault = true;
- updateActiveDefaultNetwork(newNetwork);
+ // TODO: Remove following line. It's redundant with makeDefault call.
+ mActiveDefaultNetwork = newNetwork.networkInfo.getType();
if (newNetwork.linkProperties != null) {
updateTcpBufferSizes(newNetwork);
setDefaultDnsSystemProperties(
@@ -4591,12 +4606,13 @@
mLegacyTypeTracker.remove(currentNetwork.networkInfo.getType(),
currentNetwork);
}
- mDefaultInetConditionPublished = 100;
+ mDefaultInetConditionPublished = newNetwork.validated ? 100 : 0;
mLegacyTypeTracker.add(newNetwork.networkInfo.getType(), newNetwork);
}
}
}
}
+ // Linger any networks that are no longer needed.
for (NetworkAgentInfo nai : affectedNetworks) {
boolean teardown = !nai.isVPN();
for (int i = 0; i < nai.networkRequests.size() && teardown; i++) {
@@ -4624,6 +4640,7 @@
}
if (keep) {
if (isNewDefault) {
+ // Notify system services that this network is up.
makeDefault(newNetwork);
synchronized (ConnectivityService.this) {
// have a new default network, release the transition wakelock in
@@ -4640,6 +4657,7 @@
// Notify battery stats service about this network, both the normal
// interface and any stacked links.
+ // TODO: Avoid redoing this; this must only be done once when a network comes online.
try {
final IBatteryStats bs = BatteryStatsService.getService();
final int type = newNetwork.networkInfo.getType();
@@ -4655,7 +4673,12 @@
}
notifyNetworkCallbacks(newNetwork, ConnectivityManager.CALLBACK_AVAILABLE);
- } else {
+ } else if (newNetwork.validated) {
+ // Only tear down validated networks here. Leave unvalidated to either become
+ // validated (and get evaluated against peers, one losing here) or
+ // NetworkMonitor reports a bad network and we tear it down then.
+ // TODO: Could teardown unvalidated networks when their NetworkCapabilities
+ // satisfy no NetworkRequests.
if (DBG && newNetwork.networkRequests.size() != 0) {
loge("tearing down network with live requests:");
for (int i=0; i < newNetwork.networkRequests.size(); i++) {
@@ -4667,6 +4690,31 @@
}
}
+ // Attempt to rematch all Networks with NetworkRequests. This may result in Networks
+ // being disconnected.
+ // If only one Network's score or capabilities have been modified since the last time
+ // this function was called, pass this Network in via the "changed" arugment, otherwise
+ // pass null.
+ // If only one Network has been changed but its NetworkCapabilities have not changed,
+ // pass in the Network's score (from getCurrentScore()) prior to the change via
+ // "oldScore", otherwise pass changed.getCurrentScore() or 0 if "changed" is null.
+ private void rematchAllNetworksAndRequests(NetworkAgentInfo changed, int oldScore) {
+ // TODO: This may get slow. The "changed" parameter is provided for future optimization
+ // to avoid the slowness. It is not simply enough to process just "changed", for
+ // example in the case where "changed"'s score decreases and another network should begin
+ // satifying a NetworkRequest that "changed" currently satisfies.
+
+ // Optimization: Only reprocess "changed" if its score improved. This is safe because it
+ // can only add more NetworkRequests satisfied by "changed", and this is exactly what
+ // rematchNetworkAndRequests() handles.
+ if (changed != null && oldScore < changed.getCurrentScore()) {
+ rematchNetworkAndRequests(changed);
+ } else {
+ for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+ rematchNetworkAndRequests(nai);
+ }
+ }
+ }
private void updateNetworkInfo(NetworkAgentInfo networkAgent, NetworkInfo newInfo) {
NetworkInfo.State state = newInfo.getState();
@@ -4721,12 +4769,14 @@
}
// TODO: support proxy per network.
}
- // Make default network if we have no default. Any network is better than no network.
+ // Consider network even though it is not yet validated.
+ // TODO: All the if-statement conditions can be removed now that validation only confers
+ // a score increase.
if (mNetworkForRequestId.get(mDefaultRequest.requestId) == null &&
networkAgent.isVPN() == false &&
mDefaultRequest.networkCapabilities.satisfiedByNetworkCapabilities(
networkAgent.networkCapabilities)) {
- makeDefault(networkAgent);
+ rematchNetworkAndRequests(networkAgent);
}
} else if (state == NetworkInfo.State.DISCONNECTED ||
state == NetworkInfo.State.SUSPENDED) {
@@ -4752,23 +4802,11 @@
score = 0;
}
- nai.currentScore = score;
+ final int oldScore = nai.getCurrentScore();
+ nai.setCurrentScore(score);
- // TODO - This will not do the right thing if this network is lowering
- // its score and has requests that can be served by other
- // currently-active networks, or if the network is increasing its
- // score and other networks have requests that can be better served
- // by this network.
- //
- // Really we want to see if any of our requests migrate to other
- // active/lingered networks and if any other requests migrate to us (depending
- // on increasing/decreasing currentScore. That's a bit of work and probably our
- // score checking/network allocation code needs to be modularized so we can understand
- // (see handleConnectionValided for an example).
- //
- // As a first order approx, lets just advertise the new score to factories. If
- // somebody can beat it they will nominate a network and our normal net replacement
- // code will fire.
+ if (nai.created) rematchAllNetworksAndRequests(nai, oldScore);
+
for (int i = 0; i < nai.networkRequests.size(); i++) {
NetworkRequest nr = nai.networkRequests.valueAt(i);
// Don't send listening requests to factories. b/17393458
diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java
index 2896f60..6f378fd 100644
--- a/services/core/java/com/android/server/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/PersistentDataBlockService.java
@@ -17,6 +17,7 @@
package com.android.server;
import android.Manifest;
+import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Binder;
@@ -26,7 +27,9 @@
import android.os.UserHandle;
import android.service.persistentdata.IPersistentDataBlockService;
import android.util.Slog;
+
import com.android.internal.R;
+
import libcore.io.IoUtils;
import java.io.DataInputStream;
@@ -241,6 +244,10 @@
@Override
public void setOemUnlockEnabled(boolean enabled) {
+ // do not allow monkey to flip the flag
+ if (ActivityManager.isUserAMonkey()) {
+ return;
+ }
enforceOemUnlockPermission();
FileOutputStream outputStream;
try {
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index bba786d..957d705 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -43,12 +43,16 @@
public Network network;
public LinkProperties linkProperties;
public NetworkCapabilities networkCapabilities;
- public int currentScore;
public final NetworkMonitor networkMonitor;
public final NetworkMisc networkMisc;
public boolean created;
public boolean validated;
+ // This represents the last score received from the NetworkAgent.
+ private int currentScore;
+ // Penalty applied to scores of Networks that have not been validated.
+ private static final int UNVALIDATED_SCORE_PENALTY = 40;
+
// The list of NetworkRequests being satisfied by this Network.
public final SparseArray<NetworkRequest> networkRequests = new SparseArray<NetworkRequest>();
public final ArrayList<NetworkRequest> networkLingered = new ArrayList<NetworkRequest>();
@@ -80,11 +84,33 @@
return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN);
}
+ // Get the current score for this Network. This may be modified from what the
+ // NetworkAgent sent, as it has modifiers applied to it.
+ public int getCurrentScore() {
+ // TODO: We may want to refactor this into a NetworkScore class that takes a base score from
+ // the NetworkAgent and signals from the NetworkAgent and uses those signals to modify the
+ // score. The NetworkScore class would provide a nice place to centralize score constants
+ // so they are not scattered about the transports.
+
+ int score = currentScore;
+
+ if (!validated) score -= UNVALIDATED_SCORE_PENALTY;
+
+ if (score < 0) score = 0;
+
+ return score;
+ }
+
+ public void setCurrentScore(int newScore) {
+ currentScore = newScore;
+ }
+
public String toString() {
return "NetworkAgentInfo{ ni{" + networkInfo + "} network{" +
network + "} lp{" +
linkProperties + "} nc{" +
- networkCapabilities + "} Score{" + currentScore + "} }";
+ networkCapabilities + "} Score{" + getCurrentScore() + "} " +
+ "validated{" + validated + "} created{" + created + "} }";
}
public String name() {
diff --git a/services/core/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GpsLocationProvider.java
index 11818d8..df846a8 100644
--- a/services/core/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/core/java/com/android/server/location/GpsLocationProvider.java
@@ -494,7 +494,7 @@
Log.d(TAG, "SIM STATE is ready, SIM MCC/MNC is " + mccMnc);
synchronized (mLock) {
reloadGpsProperties(context, mProperties);
- mNIHandler.setSuplEsEnablement(mSuplEsEnabled);
+ mNIHandler.setSuplEsEnabled(mSuplEsEnabled);
}
}
}
@@ -590,6 +590,7 @@
com.android.internal.R.array.config_gpsParameters);
for (String item : configValues) {
Log.d(TAG, "GpsParamsResource: " + item);
+ // We need to support "KEY =", but not "=VALUE".
String[] split = item.split("=");
if (split.length == 2) {
properties.setProperty(split[0].trim().toUpperCase(), split[1]);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index efaf253..95332bc 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3716,7 +3716,7 @@
synchronized (this) {
// Only SYSTEM_UID can override the userSetupComplete
if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID
- && isUserSetupComplete(userHandle)) {
+ && hasUserSetupCompleted(userHandle)) {
throw new IllegalStateException(
"Trying to set profile owner but user is already set-up.");
}
@@ -3773,10 +3773,14 @@
@Override
public boolean hasUserSetupCompleted() {
+ return hasUserSetupCompleted(UserHandle.getCallingUserId());
+ }
+
+ private boolean hasUserSetupCompleted(int userHandle) {
if (!mHasFeature) {
return true;
}
- DevicePolicyData policy = getUserData(UserHandle.getCallingUserId());
+ DevicePolicyData policy = getUserData(userHandle);
// If policy is null, return true, else check if the setup has completed.
return policy == null || policy.mUserSetupComplete;
}
@@ -3888,16 +3892,10 @@
if (callingId == Process.SHELL_UID || callingId == Process.ROOT_UID) {
return AccountManager.get(mContext).getAccounts().length == 0;
} else {
- return Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.DEVICE_PROVISIONED, 0) == 0;
+ return !hasUserSetupCompleted(UserHandle.USER_OWNER);
}
}
- private boolean isUserSetupComplete(int userId) {
- return Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.USER_SETUP_COMPLETE, 0, userId) > 0;
- }
-
private void enforceCrossUserPermission(int userHandle) {
if (userHandle < 0) {
throw new IllegalArgumentException("Invalid userId " + userHandle);
diff --git a/tests/VectorDrawableTest/res/anim/trim_path_animation06.xml b/tests/VectorDrawableTest/res/anim/trim_path_animation06.xml
new file mode 100644
index 0000000..1a81866
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/trim_path_animation06.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+ <objectAnimator
+ android:duration="9000"
+ android:propertyName="alpha"
+ android:valueFrom="1.0"
+ android:valueTo="0.0"/>
+
+</set>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml b/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml
index 19b82ad..8b0ceda 100644
--- a/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml
+++ b/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml
@@ -37,5 +37,8 @@
<target
android:name="rotationGroup"
android:animation="@anim/trim_path_animation04" />
+ <target
+ android:name="rootGroup"
+ android:animation="@anim/trim_path_animation06" />
</animated-vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
index 2c8b751..69ae62c 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
@@ -14,10 +14,12 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:name="rootGroup"
android:height="64dp"
android:width="64dp"
android:viewportHeight="600"
- android:viewportWidth="600" >
+ android:viewportWidth="600"
+ android:alpha="0.5" >
<group
android:name="rotationGroup"
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java
index f165cde..05bf166 100644
--- a/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java
@@ -31,6 +31,8 @@
R.drawable.animation_vector_progress_bar,
R.drawable.animation_vector_drawable_favorite,
R.drawable.animation_vector_drawable01,
+ // Duplicate to test constant state.
+ R.drawable.animation_vector_drawable01,
};
@Override