diff options
92 files changed, 1055 insertions, 455 deletions
diff --git a/api/current.txt b/api/current.txt index a66204e..e9da398 100644 --- a/api/current.txt +++ b/api/current.txt @@ -4328,9 +4328,9 @@ package android.app { method public void setAllowEnterTransitionOverlap(boolean); method public void setAllowReturnTransitionOverlap(boolean); method public void setArguments(android.os.Bundle); - method public void setEnterSharedElementTransitionCallback(android.app.SharedElementCallback); + method public void setEnterSharedElementCallback(android.app.SharedElementCallback); method public void setEnterTransition(android.transition.Transition); - method public void setExitSharedElementTransitionCallback(android.app.SharedElementCallback); + method public void setExitSharedElementCallback(android.app.SharedElementCallback); method public void setExitTransition(android.transition.Transition); method public void setHasOptionsMenu(boolean); method public void setInitialSavedState(android.app.Fragment.SavedState); 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 @@ package android.animation; import android.graphics.Path; import android.graphics.PointF; -import android.util.MathUtils; import java.util.ArrayList; @@ -64,11 +63,12 @@ class PathKeyframes implements Keyframes { @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,25 +91,29 @@ class PathKeyframes implements Keyframes { } // now high is below the fraction and low is above the fraction - int startBase = (high * NUM_COMPONENTS); - int endBase = (low * NUM_COMPONENTS); + return interpolateInRange(fraction, high, low); + } + } - float startFraction = mKeyframeData[startBase + FRACTION_OFFSET]; - float endFraction = mKeyframeData[endBase + FRACTION_OFFSET]; + private PointF interpolateInRange(float fraction, int startIndex, int endIndex) { + int startBase = (startIndex * NUM_COMPONENTS); + int endBase = (endIndex * NUM_COMPONENTS); - float intervalFraction = (fraction - startFraction)/(endFraction - startFraction); + float startFraction = mKeyframeData[startBase + FRACTION_OFFSET]; + float endFraction = mKeyframeData[endBase + FRACTION_OFFSET]; - 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 intervalFraction = (fraction - startFraction)/(endFraction - startFraction); - float x = interpolate(intervalFraction, startX, endX); - float y = interpolate(intervalFraction, startY, endY); + float startX = mKeyframeData[startBase + X_OFFSET]; + float endX = mKeyframeData[endBase + X_OFFSET]; + float startY = mKeyframeData[startBase + Y_OFFSET]; + float endY = mKeyframeData[endBase + Y_OFFSET]; - mTempPointF.set(x, y); - return mTempPointF; - } + float x = interpolate(intervalFraction, startX, endX); + float y = interpolate(intervalFraction, startY, endY); + + mTempPointF.set(x, y); + return mTempPointF; } @Override 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 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { 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 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { View view = mTransitioningViews.get(i); if (!view.getGlobalVisibleRect(r)) { mTransitioningViews.remove(i); + showView(view, true); } } } @@ -350,7 +354,10 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { 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 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { 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 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { 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 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { 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 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { 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 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { 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 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { 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 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { 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 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { 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 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { } 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 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { 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 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { 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 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { 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 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { } } - private Transition beginTransition(boolean startEnterTransition, + private Transition beginTransition(ViewGroup decorView, boolean startEnterTransition, boolean startSharedElementTransition) { Transition sharedElementTransition = null; if (startSharedElementTransition) { @@ -433,7 +448,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { 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 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { } 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 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { 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 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { 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 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { 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 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { } } - private void startSharedElementExit() { + private void startSharedElementExit(final ViewGroup decorView) { Transition transition = getSharedElementExitTransition(); transition.addListener(new Transition.TransitionListenerAdapter() { @Override @@ -165,7 +168,6 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { }); final ArrayList<View> sharedElementSnapshots = createSnapshots(mExitSharedElementBundle, mSharedElementNames); - final View decorView = getDecor(); decorView.getViewTreeObserver() .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override @@ -178,10 +180,10 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { 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 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { 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 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { 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 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { }; 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 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { 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 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { 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 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { 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/app/Fragment.java b/core/java/android/app/Fragment.java index 4374622..a95abab 100644 --- a/core/java/android/app/Fragment.java +++ b/core/java/android/app/Fragment.java @@ -1628,7 +1628,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene * @param callback Used to manipulate the shared element transitions on this Fragment * when added not as a pop from the back stack. */ - public void setEnterSharedElementTransitionCallback(SharedElementCallback callback) { + public void setEnterSharedElementCallback(SharedElementCallback callback) { if (callback == null) { callback = SharedElementCallback.NULL_CALLBACK; } @@ -1636,13 +1636,20 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene } /** + * @hide + */ + public void setEnterSharedElementTransitionCallback(SharedElementCallback callback) { + setEnterSharedElementCallback(callback); + } + + /** * When custom transitions are used with Fragments, the exit transition callback * is called when this Fragment is attached or detached when popping the back stack. * * @param callback Used to manipulate the shared element transitions on this Fragment * when added as a pop from the back stack. */ - public void setExitSharedElementTransitionCallback(SharedElementCallback callback) { + public void setExitSharedElementCallback(SharedElementCallback callback) { if (callback == null) { callback = SharedElementCallback.NULL_CALLBACK; } @@ -1650,6 +1657,13 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene } /** + * @hide + */ + public void setExitSharedElementTransitionCallback(SharedElementCallback callback) { + setExitSharedElementCallback(callback); + } + + /** * Sets the Transition that will be used to move Views into the initial scene. The entering * Views will be those that are regular Views or ViewGroups that have * {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend diff --git a/core/java/android/app/SharedElementCallback.java b/core/java/android/app/SharedElementCallback.java index 82d8e5b..d772743 100644 --- a/core/java/android/app/SharedElementCallback.java +++ b/core/java/android/app/SharedElementCallback.java @@ -32,8 +32,8 @@ import java.util.Map; * Listener provided in * {@link Activity#setEnterSharedElementCallback(SharedElementCallback)} and * {@link Activity#setExitSharedElementCallback(SharedElementCallback)} as well as - * {@link Fragment#setEnterSharedElementTransitionCallback(SharedElementCallback)} and - * {@link Fragment#setExitSharedElementTransitionCallback(SharedElementCallback)} + * {@link Fragment#setEnterSharedElementCallback(SharedElementCallback)} and + * {@link Fragment#setExitSharedElementCallback(SharedElementCallback)} * to monitor the Shared element transitions. The events can be used to customize Activity * and Fragment Transition behavior. */ 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 @@ public final class TonemapCurve { * <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 @@ public final class TonemapCurve { 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 @@ public final class TonemapCurve { 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 @@ public final class TonemapCurve { 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 @@ public final class TonemapCurve { 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 @@ public final class TonemapCurve { 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 @@ public final class Parcel { 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 @@ public final class Parcel { 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 @@ public final class Parcel { 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/java/android/transition/Transition.java b/core/java/android/transition/Transition.java index 40bb6ec..b677888 100644 --- a/core/java/android/transition/Transition.java +++ b/core/java/android/transition/Transition.java @@ -690,11 +690,18 @@ public abstract class Transition implements Cloneable { for (int i = 0; i < startValuesListCount; ++i) { TransitionValues start = startValuesList.get(i); TransitionValues end = endValuesList.get(i); - // Only bother trying to animate with valid values that differ between start/end - boolean isInvalidStart = start != null && !isValidTarget(start.view); - boolean isInvalidEnd = end != null && !isValidTarget(end.view); - boolean isChanged = start != end && (start == null || !start.equals(end)); - if (isChanged && !isInvalidStart && !isInvalidEnd) { + if (start != null && !start.targetedTransitions.contains(this)) { + start = null; + } + if (end != null && !end.targetedTransitions.contains(this)) { + end = null; + } + if (start == null && end == null) { + continue; + } + // Only bother trying to animate with values that differ between start/end + boolean isChanged = start == null || end == null || areValuesChanged(start, end); + if (isChanged) { if (DBG) { View view = (end != null) ? end.view : start.view; Log.d(LOG_TAG, " differing start/end values for view " + view); @@ -1415,11 +1422,12 @@ public abstract class Transition implements Cloneable { } else { captureEndValues(values); } + values.targetedTransitions.add(this); capturePropagationValues(values); if (start) { - addViewValues(mStartValues, view, values, true); + addViewValues(mStartValues, view, values); } else { - addViewValues(mEndValues, view, values, true); + addViewValues(mEndValues, view, values); } } } @@ -1432,6 +1440,7 @@ public abstract class Transition implements Cloneable { } else { captureEndValues(values); } + values.targetedTransitions.add(this); capturePropagationValues(values); if (start) { mStartValues.viewValues.put(view, values); @@ -1460,7 +1469,7 @@ public abstract class Transition implements Cloneable { } static void addViewValues(TransitionValuesMaps transitionValuesMaps, - View view, TransitionValues transitionValues, boolean setTransientState) { + View view, TransitionValues transitionValues) { transitionValuesMaps.viewValues.put(view, transitionValues); int id = view.getId(); if (id >= 0) { @@ -1489,15 +1498,11 @@ public abstract class Transition implements Cloneable { // Duplicate item IDs: cannot match by item ID. View alreadyMatched = transitionValuesMaps.itemIdValues.get(itemId); if (alreadyMatched != null) { - if (setTransientState) { - alreadyMatched.setHasTransientState(false); - } + alreadyMatched.setHasTransientState(false); transitionValuesMaps.itemIdValues.put(itemId, null); } } else { - if (setTransientState) { - view.setHasTransientState(true); - } + view.setHasTransientState(true); transitionValuesMaps.itemIdValues.put(itemId, view); } } @@ -1562,11 +1567,12 @@ public abstract class Transition implements Cloneable { } else { captureEndValues(values); } + values.targetedTransitions.add(this); capturePropagationValues(values); if (start) { - addViewValues(mStartValues, view, values, true); + addViewValues(mStartValues, view, values); } else { - addViewValues(mEndValues, view, values, true); + addViewValues(mEndValues, view, values); } } if (view instanceof ViewGroup) { @@ -1731,8 +1737,10 @@ public abstract class Transition implements Cloneable { if (oldInfo != null && oldInfo.view != null && oldInfo.windowId == windowId) { TransitionValues oldValues = oldInfo.values; View oldView = oldInfo.view; - TransitionValues newValues = getMatchedTransitionValues(oldView, true); - boolean cancel = oldInfo.transition.areValuesChanged(oldValues, newValues); + TransitionValues startValues = getTransitionValues(oldView, true); + TransitionValues endValues = getMatchedTransitionValues(oldView, true); + boolean cancel = (startValues != null || endValues != null) && + oldInfo.transition.areValuesChanged(oldValues, endValues); if (cancel) { if (anim.isRunning() || anim.isStarted()) { if (DBG) { @@ -1784,7 +1792,17 @@ public abstract class Transition implements Cloneable { String key) { Object oldValue = oldValues.values.get(key); Object newValue = newValues.values.get(key); - boolean changed = (oldValue != null && newValue != null && !oldValue.equals(newValue)); + boolean changed; + if (oldValue == null && newValue == null) { + // both are null + changed = false; + } else if (oldValue == null || newValue == null) { + // one is null + changed = true; + } else { + // neither is null + changed = !oldValue.equals(newValue); + } if (DBG && changed) { Log.d(LOG_TAG, "Transition.playTransition: " + "oldValue != newValue for " + key + diff --git a/core/java/android/transition/TransitionSet.java b/core/java/android/transition/TransitionSet.java index 669621eb3..09d2c69 100644 --- a/core/java/android/transition/TransitionSet.java +++ b/core/java/android/transition/TransitionSet.java @@ -388,8 +388,6 @@ public class TransitionSet extends Transition { protected void createAnimators(ViewGroup sceneRoot, TransitionValuesMaps startValues, TransitionValuesMaps endValues, ArrayList<TransitionValues> startValuesList, ArrayList<TransitionValues> endValuesList) { - startValues = removeExcludes(startValues); - endValues = removeExcludes(endValues); long startDelay = getStartDelay(); int numTransitions = mTransitions.size(); for (int i = 0; i < numTransitions; i++) { @@ -409,24 +407,6 @@ public class TransitionSet extends Transition { } } - private TransitionValuesMaps removeExcludes(TransitionValuesMaps values) { - if (mTargetIds.isEmpty() && mTargetIdExcludes == null && mTargetTypeExcludes == null - && mTargetNames == null && mTargetTypes == null - && mTargetExcludes == null && mTargetNameExcludes == null - && mTargets.isEmpty()) { - return values; - } - TransitionValuesMaps included = new TransitionValuesMaps(); - int numValues = values.viewValues.size(); - for (int i = 0; i < numValues; i++) { - View view = values.viewValues.keyAt(i); - if (isValidTarget(view)) { - addViewValues(included, view, values.viewValues.valueAt(i), false); - } - } - return included; - } - /** * @hide */ @@ -470,6 +450,7 @@ public class TransitionSet extends Transition { for (Transition childTransition : mTransitions) { if (childTransition.isValidTarget(transitionValues.view)) { childTransition.captureStartValues(transitionValues); + transitionValues.targetedTransitions.add(childTransition); } } } @@ -481,6 +462,7 @@ public class TransitionSet extends Transition { for (Transition childTransition : mTransitions) { if (childTransition.isValidTarget(transitionValues.view)) { childTransition.captureEndValues(transitionValues); + transitionValues.targetedTransitions.add(childTransition); } } } diff --git a/core/java/android/transition/TransitionValues.java b/core/java/android/transition/TransitionValues.java index 8989f89..11f2962 100644 --- a/core/java/android/transition/TransitionValues.java +++ b/core/java/android/transition/TransitionValues.java @@ -20,6 +20,7 @@ import android.util.ArrayMap; import android.view.View; import android.view.ViewGroup; +import java.util.ArrayList; import java.util.Map; /** @@ -52,6 +53,11 @@ public class TransitionValues { */ public final Map<String, Object> values = new ArrayMap<String, Object>(); + /** + * The Transitions that targeted this view. + */ + final ArrayList<Transition> targetedTransitions = new ArrayList<Transition>(); + @Override public boolean equals(Object other) { if (other instanceof TransitionValues) { diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java index ba2d5b8..1ce19ce 100644 --- a/core/java/android/widget/Toolbar.java +++ b/core/java/android/widget/Toolbar.java @@ -33,6 +33,7 @@ import android.view.Gravity; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; +import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; @@ -132,6 +133,8 @@ public class Toolbar extends ViewGroup { private int mTitleTextColor; private int mSubtitleTextColor; + private boolean mEatingTouch; + // Clear me after use. private final ArrayList<View> mTempViews = new ArrayList<View>(); @@ -1061,6 +1064,32 @@ public class Toolbar extends ViewGroup { removeCallbacks(mShowOverflowMenuRunnable); } + @Override + public boolean onTouchEvent(MotionEvent ev) { + // Toolbars always eat touch events, but should still respect the touch event dispatch + // contract. If the normal View implementation doesn't want the events, we'll just silently + // eat the rest of the gesture without reporting the events to the default implementation + // since that's what it expects. + + final int action = ev.getActionMasked(); + if (action == MotionEvent.ACTION_DOWN) { + mEatingTouch = false; + } + + if (!mEatingTouch) { + final boolean handled = super.onTouchEvent(ev); + if (action == MotionEvent.ACTION_DOWN && !handled) { + mEatingTouch = true; + } + } + + if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { + mEatingTouch = false; + } + + return true; + } + /** * @hide */ 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/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 77b451f..7a2bbc1 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -412,7 +412,7 @@ <dimen name="light_y">-200dp</dimen> <dimen name="light_z">800dp</dimen> <dimen name="light_radius">800dp</dimen> - <item type="dimen" format="float" name="ambient_shadow_alpha">0.06</item> - <item type="dimen" format="float" name="spot_shadow_alpha">0.16</item> + <item type="dimen" format="float" name="ambient_shadow_alpha">0.047</item> + <item type="dimen" format="float" name="spot_shadow_alpha">0.098</item> </resources> diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java index 2916d6c..cd6297b 100644 --- a/graphics/java/android/graphics/drawable/GradientDrawable.java +++ b/graphics/java/android/graphics/drawable/GradientDrawable.java @@ -825,7 +825,7 @@ public class GradientDrawable extends Drawable { @Override public int getOpacity() { - return (mAlpha == 255 && mGradientState.mOpaqueOverBounds) ? + return (mAlpha == 255 && mGradientState.mOpaqueOverBounds && isOpaqueForState()) ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT; } @@ -1414,12 +1414,25 @@ public class GradientDrawable extends Drawable { return mGradientState; } + private boolean isOpaqueForState() { + if (mGradientState.mStrokeWidth >= 0 && mStrokePaint != null + && !isOpaque(mStrokePaint.getColor())) { + return false; + } + + if (!isOpaque(mFillPaint.getColor())) { + return false; + } + + return true; + } + @Override public void getOutline(Outline outline) { final GradientState st = mGradientState; final Rect bounds = getBounds(); // only report non-zero alpha if shape being drawn is opaque - outline.setAlpha(st.mOpaqueOverShape ? (mAlpha / 255.0f) : 0.0f); + outline.setAlpha(st.mOpaqueOverShape && isOpaqueForState() ? (mAlpha / 255.0f) : 0.0f); switch (st.mShape) { case RECTANGLE: @@ -1617,19 +1630,6 @@ public class GradientDrawable extends Drawable { mOpaqueOverBounds = false; mOpaqueOverShape = false; - // First test opacity of all colors - if (mStrokeWidth > 0) { - if (mStrokeColorStateList != null) { - if (!mStrokeColorStateList.isOpaque()) { - return; - } - } - } - - if (mColorStateList != null && !mColorStateList.isOpaque()) { - return; - } - if (mColors != null) { for (int i = 0; i < mColors.length; i++) { if (!isOpaque(mColors[i])) { @@ -1651,10 +1651,6 @@ public class GradientDrawable extends Drawable { && mRadiusArray == null; } - private static boolean isOpaque(int color) { - return ((color >> 24) & 0xff) == 0xff; - } - public void setStroke( int width, ColorStateList colorStateList, float dashWidth, float dashGap) { mStrokeWidth = width; @@ -1690,6 +1686,10 @@ public class GradientDrawable extends Drawable { } } + static boolean isOpaque(int color) { + return ((color >> 24) & 0xff) == 0xff; + } + /** * Creates a new themed GradientDrawable based on the specified constant state. * <p> 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 @@ public class VectorDrawable extends Drawable { } 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 @@ public class VectorDrawable extends Drawable { 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 class VectorDrawable extends Drawable { } } - 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 @@ public class VectorDrawable extends Drawable { 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 @@ public class VectorDrawable extends Drawable { 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 @@ public class VectorDrawable extends Drawable { 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 @@ public class VectorDrawable extends Drawable { } 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 @@ public class VectorDrawable extends Drawable { /** * 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/libs/hwui/ShadowTessellator.cpp b/libs/hwui/ShadowTessellator.cpp index c1ffa0a..35cc7a4 100644 --- a/libs/hwui/ShadowTessellator.cpp +++ b/libs/hwui/ShadowTessellator.cpp @@ -37,7 +37,7 @@ void ShadowTessellator::tessellateAmbientShadow(bool isCasterOpaque, // A bunch of parameters to tweak the shadow. // TODO: Allow some of these changable by debug settings or APIs. - float heightFactor = 1.0f / 128; + float heightFactor = 1.0f / 86; const float geomFactor = 64; Caches& caches = Caches::getInstance(); 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.Bundle; 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 @@ public class GpsNetInitiatedHandler { // 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 class GpsNetInitiatedHandler { }; 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 @@ public class GpsNetInitiatedHandler { 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 @@ public class GpsNetInitiatedHandler { 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 @@ public class GpsNetInitiatedHandler { 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 @@ public class GpsNetInitiatedHandler { 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 @@ public class GpsNetInitiatedHandler { + " 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 @@ public class GpsNetInitiatedHandler { + " 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 @@ public class GpsNetInitiatedHandler { 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/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java index 704e4a1..54ebc6a 100644 --- a/media/java/android/media/tv/TvInputInfo.java +++ b/media/java/android/media/tv/TvInputInfo.java @@ -120,7 +120,9 @@ public final class TvInputInfo implements Parcelable { // Attributes from XML meta data. private String mSetupActivity; private String mSettingsActivity; + private int mType = TYPE_TUNER; + private HdmiDeviceInfo mHdmiDeviceInfo; private String mLabel; private Uri mIconUri; private boolean mIsConnectedToHdmiSwitch; @@ -159,7 +161,7 @@ public final class TvInputInfo implements Parcelable { * ResolveInfo, and HdmiDeviceInfo. * * @param service The ResolveInfo returned from the package manager about this TV input service. - * @param deviceInfo The HdmiDeviceInfo for a HDMI CEC logical device. + * @param hdmiDeviceInfo The HdmiDeviceInfo for a HDMI CEC logical device. * @param parentId The ID of this TV input's parent input. {@code null} if none exists. * @param iconUri The {@link android.net.Uri} to load the icon image. See * {@link android.content.ContentResolver#openInputStream}. If it is {@code null}, @@ -170,12 +172,14 @@ public final class TvInputInfo implements Parcelable { */ @SystemApi public static TvInputInfo createTvInputInfo(Context context, ResolveInfo service, - HdmiDeviceInfo deviceInfo, String parentId, String label, Uri iconUri) + HdmiDeviceInfo hdmiDeviceInfo, String parentId, String label, Uri iconUri) throws XmlPullParserException, IOException { - boolean isConnectedToHdmiSwitch = (deviceInfo.getPhysicalAddress() & 0x0FFF) != 0; - return createTvInputInfo(context, service, generateInputIdForHdmiDevice( + boolean isConnectedToHdmiSwitch = (hdmiDeviceInfo.getPhysicalAddress() & 0x0FFF) != 0; + TvInputInfo input = createTvInputInfo(context, service, generateInputIdForHdmiDevice( new ComponentName(service.serviceInfo.packageName, service.serviceInfo.name), - deviceInfo), parentId, TYPE_HDMI, label, iconUri, isConnectedToHdmiSwitch); + hdmiDeviceInfo), parentId, TYPE_HDMI, label, iconUri, isConnectedToHdmiSwitch); + input.mHdmiDeviceInfo = hdmiDeviceInfo; + return input; } /** @@ -345,15 +349,27 @@ public final class TvInputInfo implements Parcelable { } /** - * Returns the type of this TV input service. + * Returns the type of this TV input. */ public int getType() { return mType; } /** - * Returns {@code true} if this TV input is pass-though which does not have any real channels - * in TvProvider. {@code false} otherwise. + * Returns the HDMI device information of this TV input. + * @hide + */ + @SystemApi + public HdmiDeviceInfo getHdmiDeviceInfo() { + if (mType == TYPE_HDMI) { + return mHdmiDeviceInfo; + } + return null; + } + + /** + * Returns {@code true} if this TV input is pass-though which does not have any real channels in + * TvProvider. {@code false} otherwise. * * @see TvContract#buildChannelUriForPassthroughInput(String) */ @@ -480,6 +496,7 @@ public final class TvInputInfo implements Parcelable { dest.writeString(mSetupActivity); dest.writeString(mSettingsActivity); dest.writeInt(mType); + dest.writeParcelable(mHdmiDeviceInfo, flags); dest.writeParcelable(mIconUri, flags); dest.writeString(mLabel); dest.writeByte(mIsConnectedToHdmiSwitch ? (byte) 1 : 0); @@ -552,6 +569,7 @@ public final class TvInputInfo implements Parcelable { mSetupActivity = in.readString(); mSettingsActivity = in.readString(); mType = in.readInt(); + mHdmiDeviceInfo = in.readParcelable(null); mIconUri = in.readParcelable(null); mLabel = in.readString(); mIsConnectedToHdmiSwitch = in.readByte() == 1 ? true : false; diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_breadcrumb_arrow_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_breadcrumb_arrow_am_alpha.png Binary files differnew file mode 100644 index 0000000..84573f6 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_breadcrumb_arrow_am_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_cab_accept_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_cab_accept_alpha.png Binary files differnew file mode 100644 index 0000000..986d3fb --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_cab_accept_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_cab_cancel_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_cab_cancel_alpha.png Binary files differnew file mode 100644 index 0000000..ce443f9 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_cab_cancel_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_cab_select_item_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_cab_select_item_alpha.png Binary files differnew file mode 100644 index 0000000..a54e0ea --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_cab_select_item_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_dialog_alert_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_dialog_alert_alpha.png Binary files differnew file mode 100644 index 0000000..6e65716 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_dialog_alert_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_dialog_info_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_dialog_info_alpha.png Binary files differnew file mode 100644 index 0000000..35bd56e --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_dialog_info_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_album_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_album_alpha.png Binary files differnew file mode 100644 index 0000000..64aa50b --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_album_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_apk_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_apk_alpha.png Binary files differnew file mode 100644 index 0000000..7cbcb8b --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_apk_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_audio_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_audio_alpha.png Binary files differnew file mode 100644 index 0000000..d6d79ec --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_audio_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_certificate_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_certificate_alpha.png Binary files differnew file mode 100644 index 0000000..ca12928 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_certificate_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_codes_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_codes_alpha.png Binary files differnew file mode 100644 index 0000000..c4afa37 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_codes_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_compressed_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_compressed_alpha.png Binary files differnew file mode 100644 index 0000000..0b0aa04 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_compressed_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_contact_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_contact_am_alpha.png Binary files differnew file mode 100644 index 0000000..ebd0535 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_contact_am_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_event_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_event_am_alpha.png Binary files differnew file mode 100644 index 0000000..29cdbb7 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_event_am_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_excel_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_excel_alpha.png Binary files differnew file mode 100644 index 0000000..ca349b6 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_excel_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_folder_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_folder_alpha.png Binary files differnew file mode 100644 index 0000000..02249d2 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_folder_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_font_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_font_alpha.png Binary files differnew file mode 100644 index 0000000..469b911 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_font_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_generic_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_generic_am_alpha.png Binary files differnew file mode 100644 index 0000000..ef479c3 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_generic_am_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_image_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_image_alpha.png Binary files differnew file mode 100644 index 0000000..3168d6f --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_image_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_pdf_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_pdf_alpha.png Binary files differnew file mode 100644 index 0000000..9bb4d66 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_pdf_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_powerpoint_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_powerpoint_alpha.png Binary files differnew file mode 100644 index 0000000..88ba9ad --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_powerpoint_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_presentation_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_presentation_alpha.png Binary files differnew file mode 100644 index 0000000..5fe18da --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_presentation_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_spreadsheet_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_spreadsheet_am_alpha.png Binary files differnew file mode 100644 index 0000000..1d05f6f --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_spreadsheet_am_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_text_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_text_am_alpha.png Binary files differnew file mode 100644 index 0000000..c2308fe --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_text_am_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_video_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_video_am_alpha.png Binary files differnew file mode 100644 index 0000000..9a173be --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_video_am_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_word_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_word_alpha.png Binary files differnew file mode 100644 index 0000000..a564f5a --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_word_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_folder_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_folder_alpha.png Binary files differnew file mode 100644 index 0000000..c0c27a2 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_folder_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_grid_folder_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_grid_folder_alpha.png Binary files differnew file mode 100644 index 0000000..ca6be0e --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_grid_folder_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_hamburger_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_hamburger_alpha.png Binary files differnew file mode 100644 index 0000000..13b20c6 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_hamburger_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_copy_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_copy_alpha.png Binary files differnew file mode 100644 index 0000000..2dcf03e --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_copy_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_delete_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_delete_alpha.png Binary files differnew file mode 100644 index 0000000..07a78ed --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_delete_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_disconnect_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_disconnect_am_alpha.png Binary files differnew file mode 100644 index 0000000..d7eb04f --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_disconnect_am_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_new_folder_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_new_folder_am_alpha.png Binary files differnew file mode 100644 index 0000000..879bf45 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_new_folder_am_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_overflow_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_overflow_alpha.png Binary files differnew file mode 100644 index 0000000..2cd4137 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_overflow_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_rename_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_rename_am_alpha.png Binary files differnew file mode 100644 index 0000000..268049e --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_rename_am_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_search_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_search_alpha.png Binary files differnew file mode 100644 index 0000000..78fc61d --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_search_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_settings_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_settings_alpha.png Binary files differnew file mode 100644 index 0000000..36e8e68 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_settings_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_share_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_share_alpha.png Binary files differnew file mode 100644 index 0000000..68831f3 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_share_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_sortby_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_sortby_am_alpha.png Binary files differnew file mode 100644 index 0000000..827a92c --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_sortby_am_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_undo_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_undo_am_alpha.png Binary files differnew file mode 100644 index 0000000..0f12b7d --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_undo_am_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_view_grid_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_view_grid_alpha.png Binary files differnew file mode 100644 index 0000000..df1bac1 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_view_grid_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_view_list_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_view_list_alpha.png Binary files differnew file mode 100644 index 0000000..9420374 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_menu_view_list_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_open_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_open_am_alpha.png Binary files differnew file mode 100644 index 0000000..0394c5c --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_open_am_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_popout_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_popout_am_alpha.png Binary files differnew file mode 100644 index 0000000..325d374 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_popout_am_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_root_download_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_root_download_alpha.png Binary files differnew file mode 100644 index 0000000..87a5210 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_root_download_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_root_folder_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_root_folder_am_alpha.png Binary files differnew file mode 100644 index 0000000..bb41a91 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_root_folder_am_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_root_recent_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_root_recent_alpha.png Binary files differnew file mode 100644 index 0000000..baa723d --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_root_recent_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_root_sdcard_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_root_sdcard_alpha.png Binary files differnew file mode 100644 index 0000000..39c737f --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_root_sdcard_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_root_usb_light_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_root_usb_light_alpha.png Binary files differnew file mode 100644 index 0000000..88973e0 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_root_usb_light_alpha.png diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_subdirectory_arrow_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_subdirectory_arrow_am_alpha.png Binary files differnew file mode 100644 index 0000000..8fddb85 --- /dev/null +++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_subdirectory_arrow_am_alpha.png 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 @@ public final class RemotePrintDocument { private final DeathRecipient mDeathRecipient = new DeathRecipient() { @Override public void binderDied() { - mAdapterDeathObserver.onDied(); + notifyPrintingAppDied(); } }; @@ -180,7 +180,6 @@ public final class RemotePrintDocument { } catch (RemoteException re) { Log.e(LOG_TAG, "Error calling start()", re); mState = STATE_FAILED; - mAdapterDeathObserver.onDied(); } } @@ -269,7 +268,6 @@ public final class RemotePrintDocument { } catch (RemoteException re) { Log.e(LOG_TAG, "Error calling finish()", re); mState = STATE_FAILED; - mAdapterDeathObserver.onDied(); } } @@ -1108,6 +1106,15 @@ public final class RemotePrintDocument { } } + 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 final class RemotePrintDocument { 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/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java index 22a74d6..faaf0ae 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java +++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java @@ -164,6 +164,7 @@ public final class PageAdapter extends Adapter implements public void onOrientationChanged() { mColumnCount = mContext.getResources().getInteger( R.integer.preview_page_per_row_count); + notifyDataSetChanged(); } public boolean isOpened() { diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrinterRegistry.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrinterRegistry.java index 7f48217..cbc568a 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrinterRegistry.java +++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrinterRegistry.java @@ -26,7 +26,6 @@ import android.os.Message; import android.print.PrinterId; import android.print.PrinterInfo; import com.android.internal.os.SomeArgs; -import com.android.printspooler.model.PrintSpoolerService; import java.util.ArrayList; import java.util.List; diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml index a3bed4f..934ed38 100644 --- a/packages/SettingsProvider/res/values/defaults.xml +++ b/packages/SettingsProvider/res/values/defaults.xml @@ -193,9 +193,12 @@ <!-- Default for Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED, 1==on --> <integer name="def_heads_up_enabled">1</integer> - <!-- Default for Settings.Global.DEVICE_NAME $1=BRAND $2=MODEL--> + <!-- Default for Settings.Global.DEVICE_NAME $1=MANUFACTURER $2=MODEL--> <string name="def_device_name">%1$s %2$s</string> + <!-- Default for Settings.Global.DEVICE_NAME $1=MODEL--> + <string name="def_device_name_simple">%1$s</string> + <!-- Default for Settings.Secure.WAKE_GESTURE_ENABLED --> <bool name="def_wake_gesture_enabled">true</bool> diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java index 6d08970..873257c 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java @@ -70,7 +70,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { // database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion' // is properly propagated through your change. Not doing so will result in a loss of user // settings. - private static final int DATABASE_VERSION = 111; + private static final int DATABASE_VERSION = 112; private Context mContext; private int mUserHandle; @@ -1788,6 +1788,29 @@ public class DatabaseHelper extends SQLiteOpenHelper { upgradeVersion = 111; } + if (upgradeVersion < 112) { + if (mUserHandle == UserHandle.USER_OWNER) { + // When device name was added, we went with Manufacturer + Model, device name should + // actually be Model only. + // Update device name to Model if it wasn't modified by user. + db.beginTransaction(); + SQLiteStatement stmt = null; + try { + stmt = db.compileStatement("UPDATE global SET value = ? " + + " WHERE name = ? AND value = ?"); + stmt.bindString(1, getDefaultDeviceName()); // new default device name + stmt.bindString(2, Settings.Global.DEVICE_NAME); + stmt.bindString(3, getOldDefaultDeviceName()); // old default device name + stmt.execute(); + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + if (stmt != null) stmt.close(); + } + } + upgradeVersion = 112; + } + // *** Remember to update DATABASE_VERSION above! if (upgradeVersion != currentVersion) { @@ -2585,8 +2608,12 @@ public class DatabaseHelper extends SQLiteOpenHelper { return defaultValue; } + private String getOldDefaultDeviceName() { + return mContext.getResources().getString(R.string.def_device_name, + Build.MANUFACTURER, Build.MODEL); + } + private String getDefaultDeviceName() { - return mContext.getResources().getString(R.string.def_device_name, Build.MANUFACTURER, - Build.MODEL); + return mContext.getResources().getString(R.string.def_device_name_simple, Build.MODEL); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java index 18ef024..b71c9bf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java @@ -257,7 +257,7 @@ public class SignalClusterView (mMobileVisible ? "VISIBLE" : "GONE"), mMobileStrengthId, mMobileTypeId)); - mMobileType.setVisibility(!mWifiVisible || mRoaming ? View.VISIBLE : View.GONE); + mMobileType.setVisibility((mRoaming || mMobileTypeId != 0) ? View.VISIBLE : View.GONE); } } 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 4d248c2..79d769a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -128,6 +128,8 @@ public class NetworkControllerImpl extends BroadcastReceiver private boolean mConnected = false; private int mConnectedNetworkType = ConnectivityManager.TYPE_NONE; private String mConnectedNetworkTypeName; + private int mLastConnectedNetworkType = ConnectivityManager.TYPE_NONE; + private int mInetCondition = 0; private int mLastInetCondition = 0; private static final int INET_CONDITION_THRESHOLD = 50; @@ -221,7 +223,7 @@ public class NetworkControllerImpl extends BroadcastReceiver filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); filter.addAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION); - filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); + filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE); filter.addAction(ConnectivityManager.INET_CONDITION_ACTION); filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); @@ -462,7 +464,7 @@ public class NetworkControllerImpl extends BroadcastReceiver intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false), intent.getStringExtra(TelephonyIntents.EXTRA_PLMN)); refreshViews(); - } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION) || + } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE) || action.equals(ConnectivityManager.INET_CONDITION_ACTION)) { updateConnectivity(intent); refreshViews(); @@ -669,21 +671,28 @@ public class NetworkControllerImpl extends BroadcastReceiver } } + private int inetConditionForNetwork(int networkType) { + return (mInetCondition == 1 && mConnectedNetworkType == networkType) ? 1 : 0; + } + private final void updateDataNetType() { + int inetCondition; + mDataTypeIconId = mQSDataTypeIconId = 0; if (mIsWimaxEnabled && mWimaxConnected) { // wimax is a special 4g network not handled by telephony - mDataIconList = TelephonyIcons.DATA_4G[mInetCondition]; + inetCondition = inetConditionForNetwork(ConnectivityManager.TYPE_WIMAX); + mDataIconList = TelephonyIcons.DATA_4G[inetCondition]; mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_4g; - mQSDataTypeIconId = TelephonyIcons.QS_DATA_4G[mInetCondition]; + mQSDataTypeIconId = TelephonyIcons.QS_DATA_4G[inetCondition]; mContentDescriptionDataType = mContext.getString( R.string.accessibility_data_connection_4g); } else { + inetCondition = inetConditionForNetwork(ConnectivityManager.TYPE_MOBILE); + final boolean showDataTypeIcon = (inetCondition > 0); switch (mDataNetType) { case TelephonyManager.NETWORK_TYPE_UNKNOWN: if (!mShowAtLeastThreeGees) { - mDataIconList = TelephonyIcons.DATA_G[mInetCondition]; - mDataTypeIconId = 0; - mQSDataTypeIconId = 0; + mDataIconList = TelephonyIcons.DATA_G[inetCondition]; mContentDescriptionDataType = ""; break; } else { @@ -691,9 +700,10 @@ public class NetworkControllerImpl extends BroadcastReceiver } case TelephonyManager.NETWORK_TYPE_EDGE: if (!mShowAtLeastThreeGees) { - mDataIconList = TelephonyIcons.DATA_E[mInetCondition]; - mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_e; - mQSDataTypeIconId = TelephonyIcons.QS_DATA_E[mInetCondition]; + mDataIconList = TelephonyIcons.DATA_E[inetCondition]; + mDataTypeIconId = showDataTypeIcon ? + R.drawable.stat_sys_data_fully_connected_e : 0; + mQSDataTypeIconId = TelephonyIcons.QS_DATA_E[inetCondition]; mContentDescriptionDataType = mContext.getString( R.string.accessibility_data_connection_edge); break; @@ -701,9 +711,10 @@ public class NetworkControllerImpl extends BroadcastReceiver // fall through } case TelephonyManager.NETWORK_TYPE_UMTS: - mDataIconList = TelephonyIcons.DATA_3G[mInetCondition]; - mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g; - mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition]; + mDataIconList = TelephonyIcons.DATA_3G[inetCondition]; + mDataTypeIconId = showDataTypeIcon ? + R.drawable.stat_sys_data_fully_connected_3g : 0; + mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[inetCondition]; mContentDescriptionDataType = mContext.getString( R.string.accessibility_data_connection_3g); break; @@ -712,15 +723,17 @@ public class NetworkControllerImpl extends BroadcastReceiver case TelephonyManager.NETWORK_TYPE_HSPA: case TelephonyManager.NETWORK_TYPE_HSPAP: if (mHspaDataDistinguishable) { - mDataIconList = TelephonyIcons.DATA_H[mInetCondition]; - mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_h; - mQSDataTypeIconId = TelephonyIcons.QS_DATA_H[mInetCondition]; + mDataIconList = TelephonyIcons.DATA_H[inetCondition]; + mDataTypeIconId = showDataTypeIcon ? + R.drawable.stat_sys_data_fully_connected_h : 0; + mQSDataTypeIconId = TelephonyIcons.QS_DATA_H[inetCondition]; mContentDescriptionDataType = mContext.getString( R.string.accessibility_data_connection_3_5g); } else { - mDataIconList = TelephonyIcons.DATA_3G[mInetCondition]; - mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g; - mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition]; + mDataIconList = TelephonyIcons.DATA_3G[inetCondition]; + mDataTypeIconId = showDataTypeIcon ? + R.drawable.stat_sys_data_fully_connected_3g : 0; + mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[inetCondition]; mContentDescriptionDataType = mContext.getString( R.string.accessibility_data_connection_3g); } @@ -728,9 +741,10 @@ public class NetworkControllerImpl extends BroadcastReceiver case TelephonyManager.NETWORK_TYPE_CDMA: if (!mShowAtLeastThreeGees) { // display 1xRTT for IS95A/B - mDataIconList = TelephonyIcons.DATA_1X[mInetCondition]; - mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_1x; - mQSDataTypeIconId = TelephonyIcons.QS_DATA_1X[mInetCondition]; + mDataIconList = TelephonyIcons.DATA_1X[inetCondition]; + mDataTypeIconId = showDataTypeIcon ? + R.drawable.stat_sys_data_fully_connected_1x : 0; + mQSDataTypeIconId = TelephonyIcons.QS_DATA_1X[inetCondition]; mContentDescriptionDataType = mContext.getString( R.string.accessibility_data_connection_cdma); break; @@ -739,9 +753,10 @@ public class NetworkControllerImpl extends BroadcastReceiver } case TelephonyManager.NETWORK_TYPE_1xRTT: if (!mShowAtLeastThreeGees) { - mDataIconList = TelephonyIcons.DATA_1X[mInetCondition]; - mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_1x; - mQSDataTypeIconId = TelephonyIcons.QS_DATA_1X[mInetCondition]; + mDataIconList = TelephonyIcons.DATA_1X[inetCondition]; + mDataTypeIconId = showDataTypeIcon ? + R.drawable.stat_sys_data_fully_connected_1x : 0; + mQSDataTypeIconId = TelephonyIcons.QS_DATA_1X[inetCondition]; mContentDescriptionDataType = mContext.getString( R.string.accessibility_data_connection_cdma); break; @@ -752,39 +767,43 @@ public class NetworkControllerImpl extends BroadcastReceiver case TelephonyManager.NETWORK_TYPE_EVDO_A: case TelephonyManager.NETWORK_TYPE_EVDO_B: case TelephonyManager.NETWORK_TYPE_EHRPD: - mDataIconList = TelephonyIcons.DATA_3G[mInetCondition]; - mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g; - mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition]; + mDataIconList = TelephonyIcons.DATA_3G[inetCondition]; + mDataTypeIconId = showDataTypeIcon ? + R.drawable.stat_sys_data_fully_connected_3g : 0; + mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[inetCondition]; mContentDescriptionDataType = mContext.getString( R.string.accessibility_data_connection_3g); break; case TelephonyManager.NETWORK_TYPE_LTE: boolean show4GforLTE = mContext.getResources().getBoolean(R.bool.config_show4GForLTE); if (show4GforLTE) { - mDataIconList = TelephonyIcons.DATA_4G[mInetCondition]; - mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_4g; - mQSDataTypeIconId = TelephonyIcons.QS_DATA_4G[mInetCondition]; + mDataIconList = TelephonyIcons.DATA_4G[inetCondition]; + mDataTypeIconId = showDataTypeIcon ? + R.drawable.stat_sys_data_fully_connected_4g : 0; + mQSDataTypeIconId = TelephonyIcons.QS_DATA_4G[inetCondition]; mContentDescriptionDataType = mContext.getString( R.string.accessibility_data_connection_4g); } else { - mDataIconList = TelephonyIcons.DATA_LTE[mInetCondition]; - mDataTypeIconId = TelephonyIcons.ICON_LTE; - mQSDataTypeIconId = TelephonyIcons.QS_DATA_LTE[mInetCondition]; + mDataIconList = TelephonyIcons.DATA_LTE[inetCondition]; + mDataTypeIconId = showDataTypeIcon ? TelephonyIcons.ICON_LTE : 0; + mQSDataTypeIconId = TelephonyIcons.QS_DATA_LTE[inetCondition]; mContentDescriptionDataType = mContext.getString( R.string.accessibility_data_connection_lte); } break; default: if (!mShowAtLeastThreeGees) { - mDataIconList = TelephonyIcons.DATA_G[mInetCondition]; - mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_g; - mQSDataTypeIconId = TelephonyIcons.QS_DATA_G[mInetCondition]; + mDataIconList = TelephonyIcons.DATA_G[inetCondition]; + mDataTypeIconId = showDataTypeIcon ? + R.drawable.stat_sys_data_fully_connected_g : 0; + mQSDataTypeIconId = TelephonyIcons.QS_DATA_G[inetCondition]; mContentDescriptionDataType = mContext.getString( R.string.accessibility_data_connection_gprs); } else { - mDataIconList = TelephonyIcons.DATA_3G[mInetCondition]; - mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g; - mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition]; + mDataIconList = TelephonyIcons.DATA_3G[inetCondition]; + mDataTypeIconId = showDataTypeIcon ? + R.drawable.stat_sys_data_fully_connected_3g : 0; + mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[inetCondition]; mContentDescriptionDataType = mContext.getString( R.string.accessibility_data_connection_3g); } @@ -967,9 +986,10 @@ public class NetworkControllerImpl extends BroadcastReceiver } private void updateWifiIcons() { + int inetCondition = inetConditionForNetwork(ConnectivityManager.TYPE_WIFI); if (mWifiConnected) { - mWifiIconId = WifiIcons.WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel]; - mQSWifiIconId = WifiIcons.QS_WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel]; + mWifiIconId = WifiIcons.WIFI_SIGNAL_STRENGTH[inetCondition][mWifiLevel]; + mQSWifiIconId = WifiIcons.QS_WIFI_SIGNAL_STRENGTH[inetCondition][mWifiLevel]; mContentDescriptionWifi = mContext.getString( AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH[mWifiLevel]); } else { @@ -1028,10 +1048,11 @@ public class NetworkControllerImpl extends BroadcastReceiver private void updateWimaxIcons() { if (mIsWimaxEnabled) { if (mWimaxConnected) { + int inetCondition = inetConditionForNetwork(ConnectivityManager.TYPE_WIMAX); if (mWimaxIdle) mWimaxIconId = WimaxIcons.WIMAX_IDLE; else - mWimaxIconId = WimaxIcons.WIMAX_SIGNAL_STRENGTH[mInetCondition][mWimaxSignal]; + mWimaxIconId = WimaxIcons.WIMAX_SIGNAL_STRENGTH[inetCondition][mWimaxSignal]; mContentDescriptionWimax = mContext.getString( AccessibilityContentDescriptions.WIMAX_CONNECTION_STRENGTH[mWimaxSignal]); } else { @@ -1208,6 +1229,8 @@ public class NetworkControllerImpl extends BroadcastReceiver mContentDescriptionCombinedSignal = mHasMobileDataFeature ? mContentDescriptionDataType : mContentDescriptionWifi; + int inetCondition = inetConditionForNetwork(ConnectivityManager.TYPE_MOBILE); + mDataTypeIconId = 0; mQSDataTypeIconId = 0; if (isCdma()) { @@ -1266,7 +1289,8 @@ public class NetworkControllerImpl extends BroadcastReceiver || mLastWimaxIconId != mWimaxIconId || mLastDataTypeIconId != mDataTypeIconId || mLastAirplaneMode != mAirplaneMode - || mLastLocale != mLocale) + || mLastLocale != mLocale + || mLastConnectedNetworkType != mConnectedNetworkType) { // NB: the mLast*s will be updated later for (SignalCluster cluster : mSignalClusters) { @@ -1301,6 +1325,10 @@ public class NetworkControllerImpl extends BroadcastReceiver mLastInetCondition = mInetCondition; } + if (mLastConnectedNetworkType != mConnectedNetworkType) { + mLastConnectedNetworkType = mConnectedNetworkType; + } + // the wimax icon on phones if (mLastWimaxIconId != mWimaxIconId) { mLastWimaxIconId = mWimaxIconId; diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index 083aa9b..f6e2e67 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -1234,6 +1234,7 @@ public class BackupManagerService extends IBackupManager.Stub { IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_PACKAGE_ADDED); filter.addAction(Intent.ACTION_PACKAGE_REMOVED); + filter.addAction(Intent.ACTION_PACKAGE_CHANGED); filter.addDataScheme("package"); mContext.registerReceiver(mBroadcastReceiver, filter); // Register for events related to sdcard installation. @@ -1688,11 +1689,12 @@ public class BackupManagerService extends IBackupManager.Stub { String action = intent.getAction(); boolean replacing = false; boolean added = false; - boolean rebind = false; + boolean changed = false; Bundle extras = intent.getExtras(); String pkgList[] = null; if (Intent.ACTION_PACKAGE_ADDED.equals(action) || - Intent.ACTION_PACKAGE_REMOVED.equals(action)) { + Intent.ACTION_PACKAGE_REMOVED.equals(action) || + Intent.ACTION_PACKAGE_CHANGED.equals(action)) { Uri uri = intent.getData(); if (uri == null) { return; @@ -1701,7 +1703,43 @@ public class BackupManagerService extends IBackupManager.Stub { if (pkgName != null) { pkgList = new String[] { pkgName }; } - rebind = added = Intent.ACTION_PACKAGE_ADDED.equals(action); + changed = Intent.ACTION_PACKAGE_CHANGED.equals(action); + + // At package-changed we only care about looking at new transport states + if (changed) { + try { + if (MORE_DEBUG) { + Slog.i(TAG, "Package " + pkgName + " changed; rechecking"); + } + // unbind existing possibly-stale connections to that package's transports + synchronized (mTransports) { + TransportConnection conn = mTransportConnections.get(pkgName); + if (conn != null) { + final ServiceInfo svc = conn.mTransport; + ComponentName svcName = + new ComponentName(svc.packageName, svc.name); + String flatName = svcName.flattenToShortString(); + Slog.i(TAG, "Unbinding " + svcName); + + mContext.unbindService(conn); + mTransportConnections.remove(pkgName); + mTransports.remove(mTransportNames.get(flatName)); + mTransportNames.remove(flatName); + } + } + // and then (re)bind as appropriate + PackageInfo app = mPackageManager.getPackageInfo(pkgName, 0); + checkForTransportAndBind(app); + } catch (NameNotFoundException e) { + // Nope, can't find it - just ignore + if (MORE_DEBUG) { + Slog.w(TAG, "Can't find changed package " + pkgName); + } + } + return; // nothing more to do in the PACKAGE_CHANGED case + } + + added = Intent.ACTION_PACKAGE_ADDED.equals(action); replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false); } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) { added = true; @@ -1737,17 +1775,15 @@ public class BackupManagerService extends IBackupManager.Stub { // Transport maintenance: rebind to known existing transports that have // just been updated; and bind to any newly-installed transport services. - if (rebind) { - synchronized (mTransportConnections) { - final TransportConnection conn = mTransportConnections.get(packageName); - if (conn != null) { - if (DEBUG) { - Slog.i(TAG, "Transport package changed; rebinding"); - } - bindTransport(conn.mTransport); - } else { - checkForTransportAndBind(app); + synchronized (mTransports) { + final TransportConnection conn = mTransportConnections.get(packageName); + if (conn != null) { + if (MORE_DEBUG) { + Slog.i(TAG, "Transport package changed; rebinding"); } + bindTransport(conn.mTransport); + } else { + checkForTransportAndBind(app); } } @@ -1840,7 +1876,7 @@ public class BackupManagerService extends IBackupManager.Stub { intent.setComponent(svcName); TransportConnection connection; - synchronized (mTransportConnections) { + synchronized (mTransports) { connection = mTransportConnections.get(transport.packageName); if (null == connection) { connection = new TransportConnection(transport); @@ -8462,31 +8498,24 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF return list; } - // Select which transport to use for the next backup operation. If the given - // name is not one of the available transports, no action is taken and the method - // returns null. + // Select which transport to use for the next backup operation. public String selectBackupTransport(String transport) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "selectBackupTransport"); synchronized (mTransports) { - String prevTransport = null; - if (mTransports.get(transport) != null) { - final long oldId = Binder.clearCallingIdentity(); - try { - prevTransport = mCurrentTransport; - mCurrentTransport = transport; - Settings.Secure.putString(mContext.getContentResolver(), - Settings.Secure.BACKUP_TRANSPORT, transport); - } finally { - Binder.restoreCallingIdentity(oldId); - } + final long oldId = Binder.clearCallingIdentity(); + try { + String prevTransport = mCurrentTransport; + mCurrentTransport = transport; + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.BACKUP_TRANSPORT, transport); Slog.v(TAG, "selectBackupTransport() set " + mCurrentTransport + " returning " + prevTransport); - } else { - Slog.w(TAG, "Attempt to select unavailable transport " + transport); + return prevTransport; + } finally { + Binder.restoreCallingIdentity(oldId); } - return prevTransport; } } 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 @@ public class AppOpsService extends IAppOpsService.Stub { @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 @@ public class AppOpsService extends IAppOpsService.Stub { } 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 @@ public class AppOpsService extends IAppOpsService.Stub { 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..55d8c09 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -251,7 +251,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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. * @@ -1794,6 +1785,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } private boolean isLiveNetworkAgent(NetworkAgentInfo nai, String msg) { + if (nai.network == null) return false; final NetworkAgentInfo officialNai; synchronized (mNetworkForNetId) { officialNai = mNetworkForNetId.get(nai.network.netId); @@ -1933,10 +1925,16 @@ public class ConnectivityService extends IConnectivityManager.Stub { } break; } - case NetworkMonitor.EVENT_NETWORK_VALIDATED: { + case NetworkMonitor.EVENT_NETWORK_TESTED: { NetworkAgentInfo nai = (NetworkAgentInfo)msg.obj; if (isLiveNetworkAgent(nai, "EVENT_NETWORK_VALIDATED")) { - handleConnectionValidated(nai); + boolean valid = (msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID); + if (valid) { + if (DBG) log("Validated " + nai.name()); + nai.validated = true; + rematchNetworkAndRequests(nai); + } + updateInetCondition(nai, valid); } break; } @@ -2057,7 +2055,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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 +2134,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { request.networkCapabilities.satisfiedByNetworkCapabilities( existing.networkCapabilities) && (alternative == null || - alternative.currentScore < existing.currentScore)) { + alternative.getCurrentScore() < existing.getCurrentScore())) { alternative = existing; } } @@ -2169,8 +2167,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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 +2193,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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 +4515,34 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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 +4557,21 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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 +4586,16 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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 +4611,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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 +4645,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } 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 +4662,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // 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 +4678,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { } 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 +4695,46 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + // 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 updateInetCondition(NetworkAgentInfo nai, boolean valid) { + // Don't bother updating until we've graduated to validated at least once. + if (!nai.validated) return; + // For now only update icons for default connection. + // TODO: Update WiFi and cellular icons separately. b/17237507 + if (!isDefaultNetwork(nai)) return; + + int newInetCondition = valid ? 100 : 0; + // Don't repeat publish. + if (newInetCondition == mDefaultInetConditionPublished) return; + + mDefaultInetConditionPublished = newInetCondition; + sendInetConditionBroadcast(nai.networkInfo); + } private void updateNetworkInfo(NetworkAgentInfo networkAgent, NetworkInfo newInfo) { NetworkInfo.State state = newInfo.getState(); @@ -4721,12 +4789,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { } // 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 +4822,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { score = 0; } - nai.currentScore = 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. + final int oldScore = nai.getCurrentScore(); + nai.setCurrentScore(score); + + 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.SystemProperties; 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 @@ public class PersistentDataBlockService extends SystemService { @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/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 2885b83..2c39691 100755 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -413,7 +413,7 @@ public final class ActivityManagerService extends ActivityManagerNative * List of intents that were used to start the most recent tasks. */ ArrayList<TaskRecord> mRecentTasks; - ArraySet<TaskRecord> mTmpRecents = new ArraySet<TaskRecord>(); + ArrayList<TaskRecord> mTmpRecents = new ArrayList<TaskRecord>(); /** * For addAppTask: cached of the last activity component that was added. @@ -3857,6 +3857,86 @@ public final class ActivityManagerService extends ActivityManagerNative mTaskPersister.wakeup(null, true); } + // Sort by taskId + private Comparator<TaskRecord> mTaskRecordComparator = new Comparator<TaskRecord>() { + @Override + public int compare(TaskRecord lhs, TaskRecord rhs) { + return rhs.taskId - lhs.taskId; + } + }; + + // Extract the affiliates of the chain containing mRecentTasks[start]. + private int processNextAffiliateChain(int start) { + final TaskRecord startTask = mRecentTasks.get(start); + final int affiliateId = startTask.mAffiliatedTaskId; + + // Quick identification of isolated tasks. I.e. those not launched behind. + if (startTask.taskId == affiliateId && startTask.mPrevAffiliate == null && + startTask.mNextAffiliate == null) { + // There is still a slim chance that there are other tasks that point to this task + // and that the chain is so messed up that this task no longer points to them but + // the gain of this optimization outweighs the risk. + startTask.inRecents = true; + return start + 1; + } + + // Remove all tasks that are affiliated to affiliateId and put them in mTmpRecents. + mTmpRecents.clear(); + for (int i = mRecentTasks.size() - 1; i >= start; --i) { + final TaskRecord task = mRecentTasks.get(i); + if (task.mAffiliatedTaskId == affiliateId) { + mRecentTasks.remove(i); + mTmpRecents.add(task); + } + } + + // Sort them all by taskId. That is the order they were create in and that order will + // always be correct. + Collections.sort(mTmpRecents, mTaskRecordComparator); + + // Go through and fix up the linked list. + // The first one is the end of the chain and has no next. + final TaskRecord first = mTmpRecents.get(0); + first.inRecents = true; + if (first.mNextAffiliate != null) { + Slog.w(TAG, "Link error 1 first.next=" + first.mNextAffiliate); + first.setNextAffiliate(null); + mTaskPersister.wakeup(first, false); + } + // Everything in the middle is doubly linked from next to prev. + final int tmpSize = mTmpRecents.size(); + for (int i = 0; i < tmpSize - 1; ++i) { + final TaskRecord next = mTmpRecents.get(i); + final TaskRecord prev = mTmpRecents.get(i + 1); + if (next.mPrevAffiliate != prev) { + Slog.w(TAG, "Link error 2 next=" + next + " prev=" + next.mPrevAffiliate + + " setting prev=" + prev); + next.setPrevAffiliate(prev); + mTaskPersister.wakeup(next, false); + } + if (prev.mNextAffiliate != next) { + Slog.w(TAG, "Link error 3 prev=" + prev + " next=" + prev.mNextAffiliate + + " setting next=" + next); + prev.setNextAffiliate(next); + mTaskPersister.wakeup(prev, false); + } + prev.inRecents = true; + } + // The last one is the beginning of the list and has no prev. + final TaskRecord last = mTmpRecents.get(tmpSize - 1); + if (last.mPrevAffiliate != null) { + Slog.w(TAG, "Link error 4 last.prev=" + last.mPrevAffiliate); + last.setPrevAffiliate(null); + mTaskPersister.wakeup(last, false); + } + + // Insert the group back into mRecentTasks at start. + mRecentTasks.addAll(start, mTmpRecents); + + // Let the caller know where we left off. + return start + tmpSize; + } + /** * Update the recent tasks lists: make sure tasks should still be here (their * applications / activities still exist), update their availability, fixup ordering @@ -3969,51 +4049,9 @@ public final class ActivityManagerService extends ActivityManagerNative } // Verify the affiliate chain for each task. - for (int i = 0; i < N; ) { - TaskRecord task = mRecentTasks.remove(i); - if (mTmpRecents.contains(task)) { - continue; - } - int affiliatedTaskId = task.mAffiliatedTaskId; - while (true) { - TaskRecord next = task.mNextAffiliate; - if (next == null) { - break; - } - if (next.mAffiliatedTaskId != affiliatedTaskId) { - Slog.e(TAG, "Error in Recents: next.affiliatedTaskId=" + - next.mAffiliatedTaskId + " affiliatedTaskId=" + affiliatedTaskId); - task.setNextAffiliate(null); - if (next.mPrevAffiliate == task) { - next.setPrevAffiliate(null); - } - break; - } - if (next.mPrevAffiliate != task) { - Slog.e(TAG, "Error in Recents chain prev.mNextAffiliate=" + - next.mPrevAffiliate + " task=" + task); - next.setPrevAffiliate(null); - task.setNextAffiliate(null); - break; - } - if (!mRecentTasks.contains(next)) { - Slog.e(TAG, "Error in Recents: next=" + next + " not in mRecentTasks"); - task.setNextAffiliate(null); - // We know that next.mPrevAffiliate is always task, from above, so clear - // its previous affiliate. - next.setPrevAffiliate(null); - break; - } - task = next; - } - // task is now the end of the list - do { - mRecentTasks.remove(task); - mRecentTasks.add(i++, task); - mTmpRecents.add(task); - task.inRecents = true; - } while ((task = task.mPrevAffiliate) != null); + for (int i = 0; i < N; i = processNextAffiliateChain(i)) { } + mTmpRecents.clear(); // mRecentTasks is now in sorted, affiliated order. } 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 class NetworkAgentInfo { 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 @@ public class NetworkAgentInfo { 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/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java index 96872a7..9e33205 100644 --- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java +++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java @@ -95,6 +95,18 @@ public class NetworkMonitor extends StateMachine { "android.net.netmon.captive_portal_logged_in"; private static final String LOGGED_IN_RESULT = "result"; + // After a network has been tested this result can be sent with EVENT_NETWORK_TESTED. + // The network should be used as a default internet connection. It was found to be: + // 1. a functioning network providing internet access, or + // 2. a captive portal and the user decided to use it as is. + public static final int NETWORK_TEST_RESULT_VALID = 0; + // After a network has been tested this result can be sent with EVENT_NETWORK_TESTED. + // The network should not be used as a default internet connection. It was found to be: + // 1. a captive portal and the user is prompted to sign-in, or + // 2. a captive portal and the user did not want to use it, or + // 3. a broken network (e.g. DNS failed, connect failed, HTTP request failed). + public static final int NETWORK_TEST_RESULT_INVALID = 1; + private static final int BASE = Protocol.BASE_NETWORK_MONITOR; /** @@ -104,10 +116,11 @@ public class NetworkMonitor extends StateMachine { public static final int CMD_NETWORK_CONNECTED = BASE + 1; /** - * Inform ConnectivityService that the network is validated. + * Inform ConnectivityService that the network has been tested. * obj = NetworkAgentInfo + * arg1 = One of the NETWORK_TESTED_RESULT_* constants. */ - public static final int EVENT_NETWORK_VALIDATED = BASE + 2; + public static final int EVENT_NETWORK_TESTED = BASE + 2; /** * Inform NetworkMonitor to linger a network. The Monitor should @@ -216,6 +229,9 @@ public class NetworkMonitor extends StateMachine { private String mServer; private boolean mIsCaptivePortalCheckEnabled = false; + // Set if the user explicitly selected "Do not use this network" in captive portal sign-in app. + private boolean mUserDoesNotWant = false; + public boolean systemReady = false; private State mDefaultState = new DefaultState(); @@ -290,9 +306,23 @@ public class NetworkMonitor extends StateMachine { private class OfflineState extends State { @Override + public void enter() { + mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED, + NETWORK_TEST_RESULT_INVALID, 0, mNetworkAgentInfo)); + } + + @Override public boolean processMessage(Message message) { if (DBG) log(getName() + message.toString()); - return NOT_HANDLED; + switch (message.what) { + case CMD_FORCE_REEVALUATION: + // If the user has indicated they explicitly do not want to use this network, + // don't allow a reevaluation as this will be pointless and could result in + // the user being annoyed with repeated unwanted notifications. + return mUserDoesNotWant ? HANDLED : NOT_HANDLED; + default: + return NOT_HANDLED; + } } } @@ -300,8 +330,8 @@ public class NetworkMonitor extends StateMachine { @Override public void enter() { if (DBG) log("Validated"); - mConnectivityServiceHandler.sendMessage( - obtainMessage(EVENT_NETWORK_VALIDATED, mNetworkAgentInfo)); + mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED, + NETWORK_TEST_RESULT_VALID, 0, mNetworkAgentInfo)); } @Override @@ -393,6 +423,8 @@ public class NetworkMonitor extends StateMachine { @Override public void enter() { + mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED, + NETWORK_TEST_RESULT_INVALID, 0, mNetworkAgentInfo)); // Wait for user to select sign-in notifcation. mUserRespondedBroadcastReceiver = new UserRespondedBroadcastReceiver( ++mUserPromptedToken); @@ -477,6 +509,7 @@ public class NetworkMonitor extends StateMachine { if (message.arg1 != mCaptivePortalLoggedInToken) return HANDLED; if (message.arg2 == 0) { + mUserDoesNotWant = true; // TODO: Should teardown network. transitionTo(mOfflineState); } else { @@ -544,6 +577,12 @@ public class NetworkMonitor extends StateMachine { mConnectivityServiceHandler.sendMessage( obtainMessage(EVENT_NETWORK_LINGER_COMPLETE, mNetworkAgentInfo)); return HANDLED; + case CMD_FORCE_REEVALUATION: + // Ignore reevaluation attempts when lingering. A reevaluation could result + // in a transition to the validated state which would abort the linger + // timeout. Lingering is the result of score assessment; validity is + // irrelevant. + return HANDLED; default: return NOT_HANDLED; } 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 @@ public class GpsLocationProvider implements LocationProviderInterface { 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 @@ public class GpsLocationProvider implements LocationProviderInterface { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class AnimatedVectorDrawableTest extends Activity implements View.OnClick 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 |