diff options
40 files changed, 574 insertions, 123 deletions
diff --git a/api/16.txt b/api/16.txt index ec35e2169003..4cdff10880fd 100644 --- a/api/16.txt +++ b/api/16.txt @@ -3704,7 +3704,6 @@ package android.app { field public static final int FLAG_ONGOING_EVENT = 2; // 0x2 field public static final int FLAG_ONLY_ALERT_ONCE = 8; // 0x8 field public static final int FLAG_SHOW_LIGHTS = 1; // 0x1 - field public static final java.lang.String KIND_PROMO = "android.promo"; field public static final int PRIORITY_DEFAULT = 0; // 0x0 field public static final int PRIORITY_HIGH = 1; // 0x1 field public static final int PRIORITY_LOW = -1; // 0xffffffff diff --git a/api/current.txt b/api/current.txt index 43128eefeb64..9540eab67537 100644 --- a/api/current.txt +++ b/api/current.txt @@ -3705,7 +3705,6 @@ package android.app { field public static final int FLAG_ONGOING_EVENT = 2; // 0x2 field public static final int FLAG_ONLY_ALERT_ONCE = 8; // 0x8 field public static final int FLAG_SHOW_LIGHTS = 1; // 0x1 - field public static final java.lang.String KIND_PROMO = "android.promo"; field public static final int PRIORITY_DEFAULT = 0; // 0x0 field public static final int PRIORITY_HIGH = 1; // 0x1 field public static final int PRIORITY_LOW = -1; // 0xffffffff diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index 523a78d8dd6c..4edfdfb32a35 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -127,14 +127,55 @@ public class ActivityOptions { */ public static ActivityOptions makeCustomAnimation(Context context, int enterResId, int exitResId) { + return makeCustomAnimation(context, enterResId, exitResId, null, null); + } + + /** + * Create an ActivityOptions specifying a custom animation to run when + * the activity is displayed. + * + * @param context Who is defining this. This is the application that the + * animation resources will be loaded from. + * @param enterResId A resource ID of the animation resource to use for + * the incoming activity. Use 0 for no animation. + * @param exitResId A resource ID of the animation resource to use for + * the outgoing activity. Use 0 for no animation. + * @param handler If <var>listener</var> is non-null this must be a valid + * Handler on which to dispatch the callback; otherwise it should be null. + * @param listener Optional OnAnimationStartedListener to find out when the + * requested animation has started running. If for some reason the animation + * is not executed, the callback will happen immediately. + * @return Returns a new ActivityOptions object that you can use to + * supply these options as the options Bundle when starting an activity. + * @hide + */ + public static ActivityOptions makeCustomAnimation(Context context, + int enterResId, int exitResId, Handler handler, OnAnimationStartedListener listener) { ActivityOptions opts = new ActivityOptions(); opts.mPackageName = context.getPackageName(); opts.mAnimationType = ANIM_CUSTOM; opts.mCustomEnterResId = enterResId; opts.mCustomExitResId = exitResId; + opts.setListener(handler, listener); return opts; } + private void setListener(Handler handler, OnAnimationStartedListener listener) { + if (listener != null) { + final Handler h = handler; + final OnAnimationStartedListener finalListener = listener; + mAnimationStartedListener = new IRemoteCallback.Stub() { + @Override public void sendResult(Bundle data) throws RemoteException { + h.post(new Runnable() { + @Override public void run() { + finalListener.onAnimationStarted(); + } + }); + } + }; + } + } + /** * Callback for use with {@link ActivityOptions#makeThumbnailScaleUpAnimation} * to find out when the given animation has started running. @@ -258,19 +299,7 @@ public class ActivityOptions { source.getLocationOnScreen(pts); opts.mStartX = pts[0] + startX; opts.mStartY = pts[1] + startY; - if (listener != null) { - final Handler h = source.getHandler(); - final OnAnimationStartedListener finalListener = listener; - opts.mAnimationStartedListener = new IRemoteCallback.Stub() { - @Override public void sendResult(Bundle data) throws RemoteException { - h.post(new Runnable() { - @Override public void run() { - finalListener.onAnimationStarted(); - } - }); - } - }; - } + opts.setListener(source.getHandler(), listener); return opts; } @@ -284,6 +313,8 @@ public class ActivityOptions { if (mAnimationType == ANIM_CUSTOM) { mCustomEnterResId = opts.getInt(KEY_ANIM_ENTER_RES_ID, 0); mCustomExitResId = opts.getInt(KEY_ANIM_EXIT_RES_ID, 0); + mAnimationStartedListener = IRemoteCallback.Stub.asInterface( + opts.getIBinder(KEY_ANIM_START_LISTENER)); } else if (mAnimationType == ANIM_SCALE_UP) { mStartX = opts.getInt(KEY_ANIM_START_X, 0); mStartY = opts.getInt(KEY_ANIM_START_Y, 0); @@ -381,7 +412,13 @@ public class ActivityOptions { mCustomEnterResId = otherOptions.mCustomEnterResId; mCustomExitResId = otherOptions.mCustomExitResId; mThumbnail = null; - mAnimationStartedListener = null; + if (otherOptions.mAnimationStartedListener != null) { + try { + otherOptions.mAnimationStartedListener.sendResult(null); + } catch (RemoteException e) { + } + } + mAnimationStartedListener = otherOptions.mAnimationStartedListener; break; case ANIM_SCALE_UP: mAnimationType = otherOptions.mAnimationType; @@ -389,6 +426,13 @@ public class ActivityOptions { mStartY = otherOptions.mStartY; mStartWidth = otherOptions.mStartWidth; mStartHeight = otherOptions.mStartHeight; + if (otherOptions.mAnimationStartedListener != null) { + try { + otherOptions.mAnimationStartedListener.sendResult(null); + } catch (RemoteException e) { + } + } + mAnimationStartedListener = null; break; case ANIM_THUMBNAIL: case ANIM_THUMBNAIL_DELAYED: @@ -425,6 +469,8 @@ public class ActivityOptions { b.putInt(KEY_ANIM_TYPE, mAnimationType); b.putInt(KEY_ANIM_ENTER_RES_ID, mCustomEnterResId); b.putInt(KEY_ANIM_EXIT_RES_ID, mCustomExitResId); + b.putIBinder(KEY_ANIM_START_LISTENER, mAnimationStartedListener + != null ? mAnimationStartedListener.asBinder() : null); break; case ANIM_SCALE_UP: b.putInt(KEY_ANIM_TYPE, mAnimationType); diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 036008bea53d..457238acfdfb 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -417,6 +417,7 @@ public class Notification implements Parcelable public static final String KIND_EVENT = "android.event"; /** + * @hide * Notification type: promotion or advertisement. */ public static final String KIND_PROMO = "android.promo"; diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index c5a687acef48..4d4eec7101c9 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -80,7 +80,8 @@ interface IWindowManager void setFocusedApp(IBinder token, boolean moveFocusNow); void prepareAppTransition(int transit, boolean alwaysKeepCurrent); int getPendingAppTransition(); - void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim); + void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim, + IRemoteCallback startedCallback); void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth, int startHeight); void overridePendingAppTransitionThumb(in Bitmap srcThumb, int startX, int startY, diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index 0517d4b35374..d3c90553fe9c 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -443,6 +443,7 @@ public class AccessibilityNodeInfo implements Parcelable { */ public AccessibilityNodeInfo findFocus(int focus) { enforceSealed(); + enforceValidFocusType(focus); if (!canPerformRequestOverConnection(mSourceNodeId)) { return null; } @@ -472,6 +473,7 @@ public class AccessibilityNodeInfo implements Parcelable { */ public AccessibilityNodeInfo focusSearch(int direction) { enforceSealed(); + enforceValidFocusDirection(direction); if (!canPerformRequestOverConnection(mSourceNodeId)) { return null; } @@ -1330,6 +1332,36 @@ public class AccessibilityNodeInfo implements Parcelable { } } + private void enforceValidFocusDirection(int direction) { + switch (direction) { + case View.FOCUS_DOWN: + case View.FOCUS_UP: + case View.FOCUS_LEFT: + case View.FOCUS_RIGHT: + case View.FOCUS_FORWARD: + case View.FOCUS_BACKWARD: + case View.ACCESSIBILITY_FOCUS_DOWN: + case View.ACCESSIBILITY_FOCUS_UP: + case View.ACCESSIBILITY_FOCUS_LEFT: + case View.ACCESSIBILITY_FOCUS_RIGHT: + case View.ACCESSIBILITY_FOCUS_FORWARD: + case View.ACCESSIBILITY_FOCUS_BACKWARD: + return; + default: + throw new IllegalArgumentException("Unknown direction: " + direction); + } + } + + private void enforceValidFocusType(int focusType) { + switch (focusType) { + case FOCUS_INPUT: + case FOCUS_ACCESSIBILITY: + return; + default: + throw new IllegalArgumentException("Unknown focus type: " + focusType); + } + } + /** * Enforces that this instance is not sealed. * diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp index c85b09c53095..35f82a85b9f0 100644 --- a/core/jni/android/graphics/TextLayoutCache.cpp +++ b/core/jni/android/graphics/TextLayoutCache.cpp @@ -992,6 +992,10 @@ HB_Face TextLayoutShaper::getCachedHBFace(SkTypeface* typeface) { } void TextLayoutShaper::purgeCaches() { + size_t cacheSize = mCachedHBFaces.size(); + for (size_t i = 0; i < cacheSize; i++) { + HB_FreeFace(mCachedHBFaces.valueAt(i)); + } mCachedHBFaces.clear(); unrefTypefaces(); init(); diff --git a/core/res/res/drawable-hdpi/progressbar_indeterminate_holo1.png b/core/res/res/drawable-hdpi/progressbar_indeterminate_holo1.png Binary files differindex 7efb94f6c55c..43f9e0350dfc 100644 --- a/core/res/res/drawable-hdpi/progressbar_indeterminate_holo1.png +++ b/core/res/res/drawable-hdpi/progressbar_indeterminate_holo1.png diff --git a/core/res/res/drawable-hdpi/progressbar_indeterminate_holo2.png b/core/res/res/drawable-hdpi/progressbar_indeterminate_holo2.png Binary files differindex 00e687994b92..c6d95f3396ef 100644 --- a/core/res/res/drawable-hdpi/progressbar_indeterminate_holo2.png +++ b/core/res/res/drawable-hdpi/progressbar_indeterminate_holo2.png diff --git a/core/res/res/drawable-hdpi/progressbar_indeterminate_holo3.png b/core/res/res/drawable-hdpi/progressbar_indeterminate_holo3.png Binary files differindex 3ffcd6898d18..7829a3cdabb9 100644 --- a/core/res/res/drawable-hdpi/progressbar_indeterminate_holo3.png +++ b/core/res/res/drawable-hdpi/progressbar_indeterminate_holo3.png diff --git a/core/res/res/drawable-hdpi/progressbar_indeterminate_holo4.png b/core/res/res/drawable-hdpi/progressbar_indeterminate_holo4.png Binary files differindex a5e94f79fb6d..d0842f8594d4 100644 --- a/core/res/res/drawable-hdpi/progressbar_indeterminate_holo4.png +++ b/core/res/res/drawable-hdpi/progressbar_indeterminate_holo4.png diff --git a/core/res/res/drawable-hdpi/progressbar_indeterminate_holo5.png b/core/res/res/drawable-hdpi/progressbar_indeterminate_holo5.png Binary files differindex dfdeba31311c..e78b8f9c2556 100644 --- a/core/res/res/drawable-hdpi/progressbar_indeterminate_holo5.png +++ b/core/res/res/drawable-hdpi/progressbar_indeterminate_holo5.png diff --git a/core/res/res/drawable-hdpi/progressbar_indeterminate_holo6.png b/core/res/res/drawable-hdpi/progressbar_indeterminate_holo6.png Binary files differindex 5b02b13c724d..5f9f6c323744 100644 --- a/core/res/res/drawable-hdpi/progressbar_indeterminate_holo6.png +++ b/core/res/res/drawable-hdpi/progressbar_indeterminate_holo6.png diff --git a/core/res/res/drawable-hdpi/progressbar_indeterminate_holo7.png b/core/res/res/drawable-hdpi/progressbar_indeterminate_holo7.png Binary files differindex 815f31bc8387..d39c4aeeb9ac 100644 --- a/core/res/res/drawable-hdpi/progressbar_indeterminate_holo7.png +++ b/core/res/res/drawable-hdpi/progressbar_indeterminate_holo7.png diff --git a/core/res/res/drawable-hdpi/progressbar_indeterminate_holo8.png b/core/res/res/drawable-hdpi/progressbar_indeterminate_holo8.png Binary files differindex 936794c1af13..94a6fae2cac7 100644 --- a/core/res/res/drawable-hdpi/progressbar_indeterminate_holo8.png +++ b/core/res/res/drawable-hdpi/progressbar_indeterminate_holo8.png diff --git a/core/res/res/drawable-mdpi/progressbar_indeterminate_holo1.png b/core/res/res/drawable-mdpi/progressbar_indeterminate_holo1.png Binary files differindex 5a9dec3fceb2..df7d06aa987e 100644 --- a/core/res/res/drawable-mdpi/progressbar_indeterminate_holo1.png +++ b/core/res/res/drawable-mdpi/progressbar_indeterminate_holo1.png diff --git a/core/res/res/drawable-mdpi/progressbar_indeterminate_holo2.png b/core/res/res/drawable-mdpi/progressbar_indeterminate_holo2.png Binary files differindex 184b280b0e05..b5b933f7e126 100644 --- a/core/res/res/drawable-mdpi/progressbar_indeterminate_holo2.png +++ b/core/res/res/drawable-mdpi/progressbar_indeterminate_holo2.png diff --git a/core/res/res/drawable-mdpi/progressbar_indeterminate_holo3.png b/core/res/res/drawable-mdpi/progressbar_indeterminate_holo3.png Binary files differindex 96f06442fd8a..b4dccc64d53a 100644 --- a/core/res/res/drawable-mdpi/progressbar_indeterminate_holo3.png +++ b/core/res/res/drawable-mdpi/progressbar_indeterminate_holo3.png diff --git a/core/res/res/drawable-mdpi/progressbar_indeterminate_holo4.png b/core/res/res/drawable-mdpi/progressbar_indeterminate_holo4.png Binary files differindex 2393a2c39698..e61f3b3566fb 100644 --- a/core/res/res/drawable-mdpi/progressbar_indeterminate_holo4.png +++ b/core/res/res/drawable-mdpi/progressbar_indeterminate_holo4.png diff --git a/core/res/res/drawable-mdpi/progressbar_indeterminate_holo5.png b/core/res/res/drawable-mdpi/progressbar_indeterminate_holo5.png Binary files differindex 4c1d60d357e8..969ab74a0b90 100644 --- a/core/res/res/drawable-mdpi/progressbar_indeterminate_holo5.png +++ b/core/res/res/drawable-mdpi/progressbar_indeterminate_holo5.png diff --git a/core/res/res/drawable-mdpi/progressbar_indeterminate_holo6.png b/core/res/res/drawable-mdpi/progressbar_indeterminate_holo6.png Binary files differindex cb89d16b59c1..5c1aa61617d4 100644 --- a/core/res/res/drawable-mdpi/progressbar_indeterminate_holo6.png +++ b/core/res/res/drawable-mdpi/progressbar_indeterminate_holo6.png diff --git a/core/res/res/drawable-mdpi/progressbar_indeterminate_holo7.png b/core/res/res/drawable-mdpi/progressbar_indeterminate_holo7.png Binary files differindex a4f843abfb82..0946f2d42ec6 100644 --- a/core/res/res/drawable-mdpi/progressbar_indeterminate_holo7.png +++ b/core/res/res/drawable-mdpi/progressbar_indeterminate_holo7.png diff --git a/core/res/res/drawable-mdpi/progressbar_indeterminate_holo8.png b/core/res/res/drawable-mdpi/progressbar_indeterminate_holo8.png Binary files differindex ea1ee05d8c20..a900c9f8f57f 100644 --- a/core/res/res/drawable-mdpi/progressbar_indeterminate_holo8.png +++ b/core/res/res/drawable-mdpi/progressbar_indeterminate_holo8.png diff --git a/core/res/res/drawable-xhdpi/progressbar_indeterminate_holo1.png b/core/res/res/drawable-xhdpi/progressbar_indeterminate_holo1.png Binary files differindex f541e3243238..ae847c972008 100644 --- a/core/res/res/drawable-xhdpi/progressbar_indeterminate_holo1.png +++ b/core/res/res/drawable-xhdpi/progressbar_indeterminate_holo1.png diff --git a/core/res/res/drawable-xhdpi/progressbar_indeterminate_holo2.png b/core/res/res/drawable-xhdpi/progressbar_indeterminate_holo2.png Binary files differindex 4c3f686991a2..7bf3ad65fc19 100644 --- a/core/res/res/drawable-xhdpi/progressbar_indeterminate_holo2.png +++ b/core/res/res/drawable-xhdpi/progressbar_indeterminate_holo2.png diff --git a/core/res/res/drawable-xhdpi/progressbar_indeterminate_holo3.png b/core/res/res/drawable-xhdpi/progressbar_indeterminate_holo3.png Binary files differindex 42ccc4973a6a..6c6341b0d6ff 100644 --- a/core/res/res/drawable-xhdpi/progressbar_indeterminate_holo3.png +++ b/core/res/res/drawable-xhdpi/progressbar_indeterminate_holo3.png diff --git a/core/res/res/drawable-xhdpi/progressbar_indeterminate_holo4.png b/core/res/res/drawable-xhdpi/progressbar_indeterminate_holo4.png Binary files differindex e5f0cd327b82..d7bb79683eba 100644 --- a/core/res/res/drawable-xhdpi/progressbar_indeterminate_holo4.png +++ b/core/res/res/drawable-xhdpi/progressbar_indeterminate_holo4.png diff --git a/core/res/res/drawable-xhdpi/progressbar_indeterminate_holo5.png b/core/res/res/drawable-xhdpi/progressbar_indeterminate_holo5.png Binary files differindex 415494b783dd..255fcb80a199 100644 --- a/core/res/res/drawable-xhdpi/progressbar_indeterminate_holo5.png +++ b/core/res/res/drawable-xhdpi/progressbar_indeterminate_holo5.png diff --git a/core/res/res/drawable-xhdpi/progressbar_indeterminate_holo6.png b/core/res/res/drawable-xhdpi/progressbar_indeterminate_holo6.png Binary files differindex 297d7b759448..6e5207eeab1e 100644 --- a/core/res/res/drawable-xhdpi/progressbar_indeterminate_holo6.png +++ b/core/res/res/drawable-xhdpi/progressbar_indeterminate_holo6.png diff --git a/core/res/res/drawable-xhdpi/progressbar_indeterminate_holo7.png b/core/res/res/drawable-xhdpi/progressbar_indeterminate_holo7.png Binary files differindex ba152f275a2d..7223bc0ac4e0 100644 --- a/core/res/res/drawable-xhdpi/progressbar_indeterminate_holo7.png +++ b/core/res/res/drawable-xhdpi/progressbar_indeterminate_holo7.png diff --git a/core/res/res/drawable-xhdpi/progressbar_indeterminate_holo8.png b/core/res/res/drawable-xhdpi/progressbar_indeterminate_holo8.png Binary files differindex b996b94e0e3a..ebcbe51399ec 100644 --- a/core/res/res/drawable-xhdpi/progressbar_indeterminate_holo8.png +++ b/core/res/res/drawable-xhdpi/progressbar_indeterminate_holo8.png diff --git a/include/androidfw/VelocityTracker.h b/include/androidfw/VelocityTracker.h index e600c5a3ccf5..8c24219c0bfe 100644 --- a/include/androidfw/VelocityTracker.h +++ b/include/androidfw/VelocityTracker.h @@ -138,8 +138,23 @@ public: */ class LeastSquaresVelocityTrackerStrategy : public VelocityTrackerStrategy { public: + enum Weighting { + // No weights applied. All data points are equally reliable. + WEIGHTING_NONE, + + // Weight by time delta. Data points clustered together are weighted less. + WEIGHTING_DELTA, + + // Weight such that points within a certain horizon are weighed more than those + // outside of that horizon. + WEIGHTING_CENTRAL, + + // Weight such that points older than a certain amount are weighed less. + WEIGHTING_RECENT, + }; + // Degree must be no greater than Estimator::MAX_DEGREE. - LeastSquaresVelocityTrackerStrategy(uint32_t degree); + LeastSquaresVelocityTrackerStrategy(uint32_t degree, Weighting weighting = WEIGHTING_NONE); virtual ~LeastSquaresVelocityTrackerStrategy(); virtual void clear(); @@ -167,7 +182,10 @@ private: } }; + float chooseWeight(uint32_t index) const; + const uint32_t mDegree; + const Weighting mWeighting; uint32_t mIndex; Movement mMovements[HISTORY_SIZE]; }; @@ -178,7 +196,8 @@ private: */ class IntegratingVelocityTrackerStrategy : public VelocityTrackerStrategy { public: - IntegratingVelocityTrackerStrategy(); + // Degree must be 1 or 2. + IntegratingVelocityTrackerStrategy(uint32_t degree); ~IntegratingVelocityTrackerStrategy(); virtual void clear(); @@ -191,18 +210,58 @@ private: // Current state estimate for a particular pointer. struct State { nsecs_t updateTime; - bool first; + uint32_t degree; - float xpos, xvel; - float ypos, yvel; + float xpos, xvel, xaccel; + float ypos, yvel, yaccel; }; + const uint32_t mDegree; BitSet32 mPointerIdBits; State mPointerState[MAX_POINTER_ID + 1]; - static void initState(State& state, nsecs_t eventTime, float xpos, float ypos); - static void updateState(State& state, nsecs_t eventTime, float xpos, float ypos); - static void populateEstimator(const State& state, VelocityTracker::Estimator* outEstimator); + void initState(State& state, nsecs_t eventTime, float xpos, float ypos) const; + void updateState(State& state, nsecs_t eventTime, float xpos, float ypos) const; + void populateEstimator(const State& state, VelocityTracker::Estimator* outEstimator) const; +}; + + +/* + * Velocity tracker strategy used prior to ICS. + */ +class LegacyVelocityTrackerStrategy : public VelocityTrackerStrategy { +public: + LegacyVelocityTrackerStrategy(); + virtual ~LegacyVelocityTrackerStrategy(); + + virtual void clear(); + virtual void clearPointers(BitSet32 idBits); + virtual void addMovement(nsecs_t eventTime, BitSet32 idBits, + const VelocityTracker::Position* positions); + virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; + +private: + // Oldest sample to consider when calculating the velocity. + static const nsecs_t HORIZON = 200 * 1000000; // 100 ms + + // Number of samples to keep. + static const uint32_t HISTORY_SIZE = 20; + + // The minimum duration between samples when estimating velocity. + static const nsecs_t MIN_DURATION = 10 * 1000000; // 10 ms + + struct Movement { + nsecs_t eventTime; + BitSet32 idBits; + VelocityTracker::Position positions[MAX_POINTERS]; + + inline const VelocityTracker::Position& getPosition(uint32_t id) const { + return positions[idBits.getIndexOfBit(id)]; + } + }; + + uint32_t mIndex; + Movement mMovements[HISTORY_SIZE]; }; } // namespace android diff --git a/libs/androidfw/VelocityTracker.cpp b/libs/androidfw/VelocityTracker.cpp index 7300ea1bd1db..f48ec6226e70 100644 --- a/libs/androidfw/VelocityTracker.cpp +++ b/libs/androidfw/VelocityTracker.cpp @@ -161,13 +161,41 @@ VelocityTrackerStrategy* VelocityTracker::createStrategy(const char* strategy) { // of the velocity when the finger is released. return new LeastSquaresVelocityTrackerStrategy(3); } + if (!strcmp("wlsq2-delta", strategy)) { + // 2nd order weighted least squares, delta weighting. Quality: EXPERIMENTAL + return new LeastSquaresVelocityTrackerStrategy(2, + LeastSquaresVelocityTrackerStrategy::WEIGHTING_DELTA); + } + if (!strcmp("wlsq2-central", strategy)) { + // 2nd order weighted least squares, central weighting. Quality: EXPERIMENTAL + return new LeastSquaresVelocityTrackerStrategy(2, + LeastSquaresVelocityTrackerStrategy::WEIGHTING_CENTRAL); + } + if (!strcmp("wlsq2-recent", strategy)) { + // 2nd order weighted least squares, recent weighting. Quality: EXPERIMENTAL + return new LeastSquaresVelocityTrackerStrategy(2, + LeastSquaresVelocityTrackerStrategy::WEIGHTING_RECENT); + } if (!strcmp("int1", strategy)) { // 1st order integrating filter. Quality: GOOD. // Not as good as 'lsq2' because it cannot estimate acceleration but it is // more tolerant of errors. Like 'lsq1', this strategy tends to underestimate // the velocity of a fling but this strategy tends to respond to changes in // direction more quickly and accurately. - return new IntegratingVelocityTrackerStrategy(); + return new IntegratingVelocityTrackerStrategy(1); + } + if (!strcmp("int2", strategy)) { + // 2nd order integrating filter. Quality: EXPERIMENTAL. + // For comparison purposes only. Unlike 'int1' this strategy can compensate + // for acceleration but it typically overestimates the effect. + return new IntegratingVelocityTrackerStrategy(2); + } + if (!strcmp("legacy", strategy)) { + // Legacy velocity tracker algorithm. Quality: POOR. + // For comparison purposes only. This algorithm is strongly influenced by + // old data points, consistently underestimates velocity and takes a very long + // time to adjust to changes in direction. + return new LegacyVelocityTrackerStrategy(); } return NULL; } @@ -327,8 +355,9 @@ bool VelocityTracker::getEstimator(uint32_t id, Estimator* outEstimator) const { const nsecs_t LeastSquaresVelocityTrackerStrategy::HORIZON; const uint32_t LeastSquaresVelocityTrackerStrategy::HISTORY_SIZE; -LeastSquaresVelocityTrackerStrategy::LeastSquaresVelocityTrackerStrategy(uint32_t degree) : - mDegree(degree) { +LeastSquaresVelocityTrackerStrategy::LeastSquaresVelocityTrackerStrategy( + uint32_t degree, Weighting weighting) : + mDegree(degree), mWeighting(weighting) { clear(); } @@ -366,10 +395,23 @@ void LeastSquaresVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet3 * * Returns true if a solution is found, false otherwise. * - * The input consists of two vectors of data points X and Y with indices 0..m-1. + * The input consists of two vectors of data points X and Y with indices 0..m-1 + * along with a weight vector W of the same size. + * * The output is a vector B with indices 0..n that describes a polynomial - * that fits the data, such the sum of abs(Y[i] - (B[0] + B[1] X[i] + B[2] X[i]^2 ... B[n] X[i]^n)) - * for all i between 0 and m-1 is minimized. + * that fits the data, such the sum of W[i] * W[i] * abs(Y[i] - (B[0] + B[1] X[i] + * + B[2] X[i]^2 ... B[n] X[i]^n)) for all i between 0 and m-1 is minimized. + * + * Accordingly, the weight vector W should be initialized by the caller with the + * reciprocal square root of the variance of the error in each input data point. + * In other words, an ideal choice for W would be W[i] = 1 / var(Y[i]) = 1 / stddev(Y[i]). + * The weights express the relative importance of each data point. If the weights are + * all 1, then the data points are considered to be of equal importance when fitting + * the polynomial. It is a good idea to choose weights that diminish the importance + * of data points that may have higher than usual error margins. + * + * Errors among data points are assumed to be independent. W is represented here + * as a vector although in the literature it is typically taken to be a diagonal matrix. * * That is to say, the function that generated the input data can be approximated * by y(x) ~= B[0] + B[1] x + B[2] x^2 + ... + B[n] x^n. @@ -379,14 +421,15 @@ void LeastSquaresVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet3 * indicates perfect correspondence. * * This function first expands the X vector to a m by n matrix A such that - * A[i][0] = 1, A[i][1] = X[i], A[i][2] = X[i]^2, ..., A[i][n] = X[i]^n. + * A[i][0] = 1, A[i][1] = X[i], A[i][2] = X[i]^2, ..., A[i][n] = X[i]^n, then + * multiplies it by w[i]./ * * Then it calculates the QR decomposition of A yielding an m by m orthonormal matrix Q * and an m by n upper triangular matrix R. Because R is upper triangular (lower * part is all zeroes), we can simplify the decomposition into an m by n matrix * Q1 and a n by n matrix R1 such that A = Q1 R1. * - * Finally we solve the system of linear equations given by R1 B = (Qtranspose Y) + * Finally we solve the system of linear equations given by R1 B = (Qtranspose W Y) * to find B. * * For efficiency, we lay out A and Q column-wise in memory because we frequently @@ -395,17 +438,18 @@ void LeastSquaresVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet3 * http://en.wikipedia.org/wiki/Numerical_methods_for_linear_least_squares * http://en.wikipedia.org/wiki/Gram-Schmidt */ -static bool solveLeastSquares(const float* x, const float* y, uint32_t m, uint32_t n, - float* outB, float* outDet) { +static bool solveLeastSquares(const float* x, const float* y, + const float* w, uint32_t m, uint32_t n, float* outB, float* outDet) { #if DEBUG_STRATEGY - ALOGD("solveLeastSquares: m=%d, n=%d, x=%s, y=%s", int(m), int(n), - vectorToString(x, m).string(), vectorToString(y, m).string()); + ALOGD("solveLeastSquares: m=%d, n=%d, x=%s, y=%s, w=%s", int(m), int(n), + vectorToString(x, m).string(), vectorToString(y, m).string(), + vectorToString(w, m).string()); #endif - // Expand the X vector to a matrix A. + // Expand the X vector to a matrix A, pre-multiplied by the weights. float a[n][m]; // column-major order for (uint32_t h = 0; h < m; h++) { - a[0][h] = 1; + a[0][h] = w[h]; for (uint32_t i = 1; i < n; i++) { a[i][h] = a[i - 1][h] * x[h]; } @@ -462,10 +506,14 @@ static bool solveLeastSquares(const float* x, const float* y, uint32_t m, uint32 ALOGD(" - qr=%s", matrixToString(&qr[0][0], m, n, false /*rowMajor*/).string()); #endif - // Solve R B = Qt Y to find B. This is easy because R is upper triangular. + // Solve R B = Qt W Y to find B. This is easy because R is upper triangular. // We just work from bottom-right to top-left calculating B's coefficients. + float wy[m]; + for (uint32_t h = 0; h < m; h++) { + wy[h] = y[h] * w[h]; + } for (uint32_t i = n; i-- != 0; ) { - outB[i] = vectorDot(&q[i][0], y, m); + outB[i] = vectorDot(&q[i][0], wy, m); for (uint32_t j = n - 1; j > i; j--) { outB[i] -= r[i][j] * outB[j]; } @@ -476,8 +524,9 @@ static bool solveLeastSquares(const float* x, const float* y, uint32_t m, uint32 #endif // Calculate the coefficient of determination as 1 - (SSerr / SStot) where - // SSerr is the residual sum of squares (squared variance of the error), - // and SStot is the total sum of squares (squared variance of the data). + // SSerr is the residual sum of squares (variance of the error), + // and SStot is the total sum of squares (variance of the data) where each + // has been weighted. float ymean = 0; for (uint32_t h = 0; h < m; h++) { ymean += y[h]; @@ -493,9 +542,9 @@ static bool solveLeastSquares(const float* x, const float* y, uint32_t m, uint32 term *= x[h]; err -= term * outB[i]; } - sserr += err * err; + sserr += w[h] * w[h] * err * err; float var = y[h] - ymean; - sstot += var * var; + sstot += w[h] * w[h] * var * var; } *outDet = sstot > 0.000001f ? 1.0f - (sserr / sstot) : 1; #if DEBUG_STRATEGY @@ -513,6 +562,7 @@ bool LeastSquaresVelocityTrackerStrategy::getEstimator(uint32_t id, // Iterate over movement samples in reverse time order and collect samples. float x[HISTORY_SIZE]; float y[HISTORY_SIZE]; + float w[HISTORY_SIZE]; float time[HISTORY_SIZE]; uint32_t m = 0; uint32_t index = mIndex; @@ -531,6 +581,7 @@ bool LeastSquaresVelocityTrackerStrategy::getEstimator(uint32_t id, const VelocityTracker::Position& position = movement.getPosition(id); x[m] = position.x; y[m] = position.y; + w[m] = chooseWeight(index); time[m] = -age * 0.000000001f; index = (index == 0 ? HISTORY_SIZE : index) - 1; } while (++m < HISTORY_SIZE); @@ -547,8 +598,8 @@ bool LeastSquaresVelocityTrackerStrategy::getEstimator(uint32_t id, if (degree >= 1) { float xdet, ydet; uint32_t n = degree + 1; - if (solveLeastSquares(time, x, m, n, outEstimator->xCoeff, &xdet) - && solveLeastSquares(time, y, m, n, outEstimator->yCoeff, &ydet)) { + if (solveLeastSquares(time, x, w, m, n, outEstimator->xCoeff, &xdet) + && solveLeastSquares(time, y, w, m, n, outEstimator->yCoeff, &ydet)) { outEstimator->time = newestMovement.eventTime; outEstimator->degree = degree; outEstimator->confidence = xdet * ydet; @@ -572,10 +623,78 @@ bool LeastSquaresVelocityTrackerStrategy::getEstimator(uint32_t id, return true; } +float LeastSquaresVelocityTrackerStrategy::chooseWeight(uint32_t index) const { + switch (mWeighting) { + case WEIGHTING_DELTA: { + // Weight points based on how much time elapsed between them and the next + // point so that points that "cover" a shorter time span are weighed less. + // delta 0ms: 0.5 + // delta 10ms: 1.0 + if (index == mIndex) { + return 1.0f; + } + uint32_t nextIndex = (index + 1) % HISTORY_SIZE; + float deltaMillis = (mMovements[nextIndex].eventTime- mMovements[index].eventTime) + * 0.000001f; + if (deltaMillis < 0) { + return 0.5f; + } + if (deltaMillis < 10) { + return 0.5f + deltaMillis * 0.05; + } + return 1.0f; + } + + case WEIGHTING_CENTRAL: { + // Weight points based on their age, weighing very recent and very old points less. + // age 0ms: 0.5 + // age 10ms: 1.0 + // age 50ms: 1.0 + // age 60ms: 0.5 + float ageMillis = (mMovements[mIndex].eventTime - mMovements[index].eventTime) + * 0.000001f; + if (ageMillis < 0) { + return 0.5f; + } + if (ageMillis < 10) { + return 0.5f + ageMillis * 0.05; + } + if (ageMillis < 50) { + return 1.0f; + } + if (ageMillis < 60) { + return 0.5f + (60 - ageMillis) * 0.05; + } + return 0.5f; + } + + case WEIGHTING_RECENT: { + // Weight points based on their age, weighing older points less. + // age 0ms: 1.0 + // age 50ms: 1.0 + // age 100ms: 0.5 + float ageMillis = (mMovements[mIndex].eventTime - mMovements[index].eventTime) + * 0.000001f; + if (ageMillis < 50) { + return 1.0f; + } + if (ageMillis < 100) { + return 0.5f + (100 - ageMillis) * 0.01f; + } + return 0.5f; + } + + case WEIGHTING_NONE: + default: + return 1.0f; + } +} + // --- IntegratingVelocityTrackerStrategy --- -IntegratingVelocityTrackerStrategy::IntegratingVelocityTrackerStrategy() { +IntegratingVelocityTrackerStrategy::IntegratingVelocityTrackerStrategy(uint32_t degree) : + mDegree(degree) { } IntegratingVelocityTrackerStrategy::~IntegratingVelocityTrackerStrategy() { @@ -620,18 +739,20 @@ bool IntegratingVelocityTrackerStrategy::getEstimator(uint32_t id, } void IntegratingVelocityTrackerStrategy::initState(State& state, - nsecs_t eventTime, float xpos, float ypos) { + nsecs_t eventTime, float xpos, float ypos) const { state.updateTime = eventTime; - state.first = true; + state.degree = 0; state.xpos = xpos; state.xvel = 0; + state.xaccel = 0; state.ypos = ypos; state.yvel = 0; + state.yaccel = 0; } void IntegratingVelocityTrackerStrategy::updateState(State& state, - nsecs_t eventTime, float xpos, float ypos) { + nsecs_t eventTime, float xpos, float ypos) const { const nsecs_t MIN_TIME_DELTA = 2 * NANOS_PER_MS; const float FILTER_TIME_CONSTANT = 0.010f; // 10 milliseconds @@ -644,28 +765,164 @@ void IntegratingVelocityTrackerStrategy::updateState(State& state, float xvel = (xpos - state.xpos) / dt; float yvel = (ypos - state.ypos) / dt; - if (state.first) { + if (state.degree == 0) { state.xvel = xvel; state.yvel = yvel; - state.first = false; + state.degree = 1; } else { float alpha = dt / (FILTER_TIME_CONSTANT + dt); - state.xvel += (xvel - state.xvel) * alpha; - state.yvel += (yvel - state.yvel) * alpha; + if (mDegree == 1) { + state.xvel += (xvel - state.xvel) * alpha; + state.yvel += (yvel - state.yvel) * alpha; + } else { + float xaccel = (xvel - state.xvel) / dt; + float yaccel = (yvel - state.yvel) / dt; + if (state.degree == 1) { + state.xaccel = xaccel; + state.yaccel = yaccel; + state.degree = 2; + } else { + state.xaccel += (xaccel - state.xaccel) * alpha; + state.yaccel += (yaccel - state.yaccel) * alpha; + } + state.xvel += (state.xaccel * dt) * alpha; + state.yvel += (state.yaccel * dt) * alpha; + } } state.xpos = xpos; state.ypos = ypos; } void IntegratingVelocityTrackerStrategy::populateEstimator(const State& state, - VelocityTracker::Estimator* outEstimator) { + VelocityTracker::Estimator* outEstimator) const { outEstimator->time = state.updateTime; - outEstimator->degree = 1; outEstimator->confidence = 1.0f; + outEstimator->degree = state.degree; outEstimator->xCoeff[0] = state.xpos; outEstimator->xCoeff[1] = state.xvel; + outEstimator->xCoeff[2] = state.xaccel / 2; outEstimator->yCoeff[0] = state.ypos; outEstimator->yCoeff[1] = state.yvel; + outEstimator->yCoeff[2] = state.yaccel / 2; +} + + +// --- LegacyVelocityTrackerStrategy --- + +const nsecs_t LegacyVelocityTrackerStrategy::HORIZON; +const uint32_t LegacyVelocityTrackerStrategy::HISTORY_SIZE; +const nsecs_t LegacyVelocityTrackerStrategy::MIN_DURATION; + +LegacyVelocityTrackerStrategy::LegacyVelocityTrackerStrategy() { + clear(); +} + +LegacyVelocityTrackerStrategy::~LegacyVelocityTrackerStrategy() { +} + +void LegacyVelocityTrackerStrategy::clear() { + mIndex = 0; + mMovements[0].idBits.clear(); +} + +void LegacyVelocityTrackerStrategy::clearPointers(BitSet32 idBits) { + BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value); + mMovements[mIndex].idBits = remainingIdBits; +} + +void LegacyVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits, + const VelocityTracker::Position* positions) { + if (++mIndex == HISTORY_SIZE) { + mIndex = 0; + } + + Movement& movement = mMovements[mIndex]; + movement.eventTime = eventTime; + movement.idBits = idBits; + uint32_t count = idBits.count(); + for (uint32_t i = 0; i < count; i++) { + movement.positions[i] = positions[i]; + } +} + +bool LegacyVelocityTrackerStrategy::getEstimator(uint32_t id, + VelocityTracker::Estimator* outEstimator) const { + outEstimator->clear(); + + const Movement& newestMovement = mMovements[mIndex]; + if (!newestMovement.idBits.hasBit(id)) { + return false; // no data + } + + // Find the oldest sample that contains the pointer and that is not older than HORIZON. + nsecs_t minTime = newestMovement.eventTime - HORIZON; + uint32_t oldestIndex = mIndex; + uint32_t numTouches = 1; + do { + uint32_t nextOldestIndex = (oldestIndex == 0 ? HISTORY_SIZE : oldestIndex) - 1; + const Movement& nextOldestMovement = mMovements[nextOldestIndex]; + if (!nextOldestMovement.idBits.hasBit(id) + || nextOldestMovement.eventTime < minTime) { + break; + } + oldestIndex = nextOldestIndex; + } while (++numTouches < HISTORY_SIZE); + + // Calculate an exponentially weighted moving average of the velocity estimate + // at different points in time measured relative to the oldest sample. + // This is essentially an IIR filter. Newer samples are weighted more heavily + // than older samples. Samples at equal time points are weighted more or less + // equally. + // + // One tricky problem is that the sample data may be poorly conditioned. + // Sometimes samples arrive very close together in time which can cause us to + // overestimate the velocity at that time point. Most samples might be measured + // 16ms apart but some consecutive samples could be only 0.5sm apart because + // the hardware or driver reports them irregularly or in bursts. + float accumVx = 0; + float accumVy = 0; + uint32_t index = oldestIndex; + uint32_t samplesUsed = 0; + const Movement& oldestMovement = mMovements[oldestIndex]; + const VelocityTracker::Position& oldestPosition = oldestMovement.getPosition(id); + nsecs_t lastDuration = 0; + + while (numTouches-- > 1) { + if (++index == HISTORY_SIZE) { + index = 0; + } + const Movement& movement = mMovements[index]; + nsecs_t duration = movement.eventTime - oldestMovement.eventTime; + + // If the duration between samples is small, we may significantly overestimate + // the velocity. Consequently, we impose a minimum duration constraint on the + // samples that we include in the calculation. + if (duration >= MIN_DURATION) { + const VelocityTracker::Position& position = movement.getPosition(id); + float scale = 1000000000.0f / duration; // one over time delta in seconds + float vx = (position.x - oldestPosition.x) * scale; + float vy = (position.y - oldestPosition.y) * scale; + accumVx = (accumVx * lastDuration + vx * duration) / (duration + lastDuration); + accumVy = (accumVy * lastDuration + vy * duration) / (duration + lastDuration); + lastDuration = duration; + samplesUsed += 1; + } + } + + // Report velocity. + const VelocityTracker::Position& newestPosition = newestMovement.getPosition(id); + outEstimator->time = newestMovement.eventTime; + outEstimator->confidence = 1; + outEstimator->xCoeff[0] = newestPosition.x; + outEstimator->yCoeff[0] = newestPosition.y; + if (samplesUsed) { + outEstimator->xCoeff[1] = accumVx; + outEstimator->yCoeff[1] = accumVy; + outEstimator->degree = 1; + } else { + outEstimator->degree = 0; + } + return true; } } // namespace android diff --git a/packages/SystemUI/res/anim/search_launch_enter.xml b/packages/SystemUI/res/anim/search_launch_enter.xml index 055ea5d795fa..f3333b7cd816 100644 --- a/packages/SystemUI/res/anim/search_launch_enter.xml +++ b/packages/SystemUI/res/anim/search_launch_enter.xml @@ -22,10 +22,10 @@ <alpha android:fromAlpha="0" android:toAlpha="1.0" android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true" - android:interpolator="@android:interpolator/decelerate_quad" + android:interpolator="@android:interpolator/decelerate_cubic" android:duration="300"/> - <translate android:fromYDelta="200" android:toYDelta="0" + <translate android:fromYDelta="100%" android:toYDelta="0" android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true" android:interpolator="@android:interpolator/decelerate_cubic" android:duration="300" /> diff --git a/packages/SystemUI/src/com/android/systemui/SearchPanelView.java b/packages/SystemUI/src/com/android/systemui/SearchPanelView.java index 1cd8d503ca26..8b8a814cd3f6 100644 --- a/packages/SystemUI/src/com/android/systemui/SearchPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/SearchPanelView.java @@ -46,8 +46,8 @@ import com.android.systemui.statusbar.tablet.StatusBarPanel; import com.android.systemui.statusbar.tablet.TabletStatusBar; public class SearchPanelView extends FrameLayout implements - StatusBarPanel { - private static final int SEARCH_PANEL_HOLD_DURATION = 500; + StatusBarPanel, ActivityOptions.OnAnimationStartedListener { + private static final int SEARCH_PANEL_HOLD_DURATION = 0; static final String TAG = "SearchPanelView"; static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false; private static final String ASSIST_ICON_METADATA_NAME = @@ -115,18 +115,18 @@ public class SearchPanelView extends FrameLayout implements if (intent == null) return; try { ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext, - R.anim.search_launch_enter, R.anim.search_launch_exit); + R.anim.search_launch_enter, R.anim.search_launch_exit, + getHandler(), this); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mContext.startActivity(intent, opts.toBundle()); } catch (ActivityNotFoundException e) { Slog.w(TAG, "Activity not found for " + intent.getAction()); + onAnimationStarted(); } } - final MultiWaveView.OnTriggerListener mMultiWaveViewListener - = new MultiWaveView.OnTriggerListener() { - - private boolean mWaitingForLaunch; + class MultiWaveTriggerListener implements MultiWaveView.OnTriggerListener { + boolean mWaitingForLaunch; public void onGrabbed(View v, int handle) { } @@ -147,19 +147,24 @@ public class SearchPanelView extends FrameLayout implements mWaitingForLaunch = true; startAssistActivity(); vibrate(); - postDelayed(new Runnable() { - public void run() { - mWaitingForLaunch = false; - mBar.hideSearchPanel(); - } - }, SEARCH_PANEL_HOLD_DURATION); break; } } public void onFinishFinalAnimation() { } - }; + } + final MultiWaveTriggerListener mMultiWaveViewListener = new MultiWaveTriggerListener(); + + @Override + public void onAnimationStarted() { + postDelayed(new Runnable() { + public void run() { + mMultiWaveViewListener.mWaitingForLaunch = false; + mBar.hideSearchPanel(); + } + }, SEARCH_PANEL_HOLD_DURATION); + } @Override protected void onFinishInflate() { diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index febbd3234d5e..8245d671ba87 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -2804,7 +2804,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (self.state == ActivityState.RESUMED || self.state == ActivityState.PAUSING) { mWindowManager.overridePendingAppTransition(packageName, - enterAnim, exitAnim); + enterAnim, exitAnim, null); } Binder.restoreCallingIdentity(origId); diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java index ad80273bc02b..26c5c3d952fb 100644 --- a/services/java/com/android/server/am/ActivityRecord.java +++ b/services/java/com/android/server/am/ActivityRecord.java @@ -558,7 +558,8 @@ final class ActivityRecord { service.mWindowManager.overridePendingAppTransition( pendingOptions.getPackageName(), pendingOptions.getCustomEnterResId(), - pendingOptions.getCustomExitResId()); + pendingOptions.getCustomExitResId(), + pendingOptions.getOnAnimationStartListener()); break; case ActivityOptions.ANIM_SCALE_UP: service.mWindowManager.overridePendingAppTransitionScaleUp( diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index 5b15e50cc05c..6af7a88aed90 100755 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -1371,6 +1371,10 @@ final class ActivityStack { * nothing happened. */ final boolean resumeTopActivityLocked(ActivityRecord prev) { + return resumeTopActivityLocked(prev, null); + } + + final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) { // Find the first activity that is not finishing. ActivityRecord next = topRunningActivityLocked(null); @@ -1383,6 +1387,7 @@ final class ActivityStack { // There are no more activities! Let's just start up the // Launcher... if (mMainStack) { + ActivityOptions.abort(options); return mService.startHomeActivityLocked(0); } } @@ -1395,6 +1400,7 @@ final class ActivityStack { // should be nothing left to do at this point. mService.mWindowManager.executeAppTransition(); mNoAnimActivities.clear(); + ActivityOptions.abort(options); return false; } @@ -1409,6 +1415,7 @@ final class ActivityStack { // should be nothing left to do at this point. mService.mWindowManager.executeAppTransition(); mNoAnimActivities.clear(); + ActivityOptions.abort(options); return false; } @@ -1419,6 +1426,8 @@ final class ActivityStack { next.sleeping = false; mWaitingVisibleActivities.remove(next); + next.updateOptionsLocked(options); + if (DEBUG_SWITCH) Slog.v(TAG, "Resuming " + next); // If we are currently pausing an activity, then don't do anything @@ -2666,6 +2675,7 @@ final class ActivityStack { movedHome = true; moveHomeToFrontFromLaunchLocked(launchFlags); moveTaskToFrontLocked(taskTop.task, r, options); + options = null; } } // If the caller has requested that the target task be @@ -2679,9 +2689,10 @@ final class ActivityStack { // is the case, so this is it! And for paranoia, make // sure we have correctly resumed the top activity. if (doResume) { - resumeTopActivityLocked(null); + resumeTopActivityLocked(null, options); + } else { + ActivityOptions.abort(options); } - ActivityOptions.abort(options); return ActivityManager.START_RETURN_INTENT_TO_CALLER; } if ((launchFlags & @@ -2767,9 +2778,10 @@ final class ActivityStack { // don't use that intent!) And for paranoia, make // sure we have correctly resumed the top activity. if (doResume) { - resumeTopActivityLocked(null); + resumeTopActivityLocked(null, options); + } else { + ActivityOptions.abort(options); } - ActivityOptions.abort(options); return ActivityManager.START_TASK_TO_FRONT; } } diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 20532996f85e..9257028f0f37 100755 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -3258,13 +3258,15 @@ public class WindowManagerService extends IWindowManager.Stub if (mNextAppTransitionType == ActivityOptions.ANIM_CUSTOM) { a = loadAnimation(mNextAppTransitionPackage, enter ? mNextAppTransitionEnter : mNextAppTransitionExit); - if (DEBUG_ANIM) Slog.v(TAG, "applyAnimation: wtoken=" + wtoken + if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, + "applyAnimation: wtoken=" + wtoken + " anim=" + a + " nextAppTransition=ANIM_CUSTOM" + " transit=" + transit + " Callers " + Debug.getCallers(3)); } else if (mNextAppTransitionType == ActivityOptions.ANIM_SCALE_UP) { a = createScaleUpAnimationLocked(transit, enter); initialized = true; - if (DEBUG_ANIM) Slog.v(TAG, "applyAnimation: wtoken=" + wtoken + if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, + "applyAnimation: wtoken=" + wtoken + " anim=" + a + " nextAppTransition=ANIM_SCALE_UP" + " transit=" + transit + " Callers " + Debug.getCallers(3)); } else if (mNextAppTransitionType == ActivityOptions.ANIM_THUMBNAIL || @@ -3273,7 +3275,7 @@ public class WindowManagerService extends IWindowManager.Stub a = createThumbnailAnimationLocked(transit, enter, false, delayed); initialized = true; - if (DEBUG_ANIM) { + if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) { String animName = delayed ? "ANIM_THUMBNAIL_DELAYED" : "ANIM_THUMBNAIL"; Slog.v(TAG, "applyAnimation: wtoken=" + wtoken + " anim=" + a + " nextAppTransition=" + animName @@ -3334,7 +3336,8 @@ public class WindowManagerService extends IWindowManager.Stub break; } a = animAttr != 0 ? loadAnimation(lp, animAttr) : null; - if (DEBUG_ANIM) Slog.v(TAG, "applyAnimation: wtoken=" + wtoken + if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, + "applyAnimation: wtoken=" + wtoken + " anim=" + a + " animAttr=0x" + Integer.toHexString(animAttr) + " transit=" + transit + " Callers " + Debug.getCallers(3)); @@ -3897,41 +3900,62 @@ public class WindowManagerService extends IWindowManager.Stub return mNextAppTransition; } + private void scheduleAnimationCallback(IRemoteCallback cb) { + if (cb != null) { + mH.sendMessage(mH.obtainMessage(H.DO_ANIMATION_CALLBACK, cb)); + } + } + public void overridePendingAppTransition(String packageName, - int enterAnim, int exitAnim) { - if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { - mNextAppTransitionType = ActivityOptions.ANIM_CUSTOM; - mNextAppTransitionPackage = packageName; - mNextAppTransitionThumbnail = null; - mNextAppTransitionEnter = enterAnim; - mNextAppTransitionExit = exitAnim; + int enterAnim, int exitAnim, IRemoteCallback startedCallback) { + synchronized(mWindowMap) { + if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { + mNextAppTransitionType = ActivityOptions.ANIM_CUSTOM; + mNextAppTransitionPackage = packageName; + mNextAppTransitionThumbnail = null; + mNextAppTransitionEnter = enterAnim; + mNextAppTransitionExit = exitAnim; + scheduleAnimationCallback(mNextAppTransitionCallback); + mNextAppTransitionCallback = startedCallback; + } else { + scheduleAnimationCallback(startedCallback); + } } } public void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth, int startHeight) { - if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { - mNextAppTransitionType = ActivityOptions.ANIM_SCALE_UP; - mNextAppTransitionPackage = null; - mNextAppTransitionThumbnail = null; - mNextAppTransitionStartX = startX; - mNextAppTransitionStartY = startY; - mNextAppTransitionStartWidth = startWidth; - mNextAppTransitionStartHeight = startHeight; + synchronized(mWindowMap) { + if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { + mNextAppTransitionType = ActivityOptions.ANIM_SCALE_UP; + mNextAppTransitionPackage = null; + mNextAppTransitionThumbnail = null; + mNextAppTransitionStartX = startX; + mNextAppTransitionStartY = startY; + mNextAppTransitionStartWidth = startWidth; + mNextAppTransitionStartHeight = startHeight; + scheduleAnimationCallback(mNextAppTransitionCallback); + mNextAppTransitionCallback = null; + } } } public void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX, int startY, IRemoteCallback startedCallback, boolean delayed) { - if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { - mNextAppTransitionType = - delayed ? ActivityOptions.ANIM_THUMBNAIL_DELAYED : ActivityOptions.ANIM_THUMBNAIL; - mNextAppTransitionPackage = null; - mNextAppTransitionThumbnail = srcThumb; - mNextAppTransitionDelayed = delayed; - mNextAppTransitionStartX = startX; - mNextAppTransitionStartY = startY; - mNextAppTransitionCallback = startedCallback; + synchronized(mWindowMap) { + if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { + mNextAppTransitionType = delayed + ? ActivityOptions.ANIM_THUMBNAIL_DELAYED : ActivityOptions.ANIM_THUMBNAIL; + mNextAppTransitionPackage = null; + mNextAppTransitionThumbnail = srcThumb; + mNextAppTransitionDelayed = delayed; + mNextAppTransitionStartX = startX; + mNextAppTransitionStartY = startY; + scheduleAnimationCallback(mNextAppTransitionCallback); + mNextAppTransitionCallback = startedCallback; + } else { + scheduleAnimationCallback(startedCallback); + } } } @@ -6797,6 +6821,7 @@ public class WindowManagerService extends IWindowManager.Stub public static final int WAITING_FOR_DRAWN_TIMEOUT = 24; public static final int BULK_UPDATE_PARAMETERS = 25; public static final int SHOW_STRICT_MODE_VIOLATION = 26; + public static final int DO_ANIMATION_CALLBACK = 27; public static final int ANIMATOR_WHAT_OFFSET = 100000; public static final int SET_TRANSPARENT_REGION = ANIMATOR_WHAT_OFFSET + 1; @@ -7297,6 +7322,14 @@ public class WindowManagerService extends IWindowManager.Stub mAnimator.clearPendingActions(); break; } + + case DO_ANIMATION_CALLBACK: { + try { + ((IRemoteCallback)msg.obj).sendResult(null); + } catch (RemoteException e) { + } + break; + } } if (DEBUG_WINDOW_TRACE) { Slog.v(TAG, "handleMessage: exit"); @@ -8012,6 +8045,7 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New wallpaper target=" + mWallpaperTarget + + ", oldWallpaper=" + oldWallpaper + ", lower target=" + mLowerWallpaperTarget + ", upper target=" + mUpperWallpaperTarget); int foundWallpapers = 0; @@ -8078,7 +8112,7 @@ public class WindowManagerService extends IWindowManager.Stub } if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit: " + transit); - } else if (oldWallpaper != null) { + } else if ((oldWallpaper != null) && !mOpeningApps.contains(oldWallpaper.mAppToken)) { // We are transitioning from an activity with // a wallpaper to one without. transit = WindowManagerPolicy.TRANSIT_WALLPAPER_CLOSE; @@ -8103,7 +8137,6 @@ public class WindowManagerService extends IWindowManager.Stub AppWindowToken topOpeningApp = null; int topOpeningLayer = 0; - // TODO(cmautner): Move to animation side. NN = mOpeningApps.size(); for (i=0; i<NN; i++) { AppWindowToken wtoken = mOpeningApps.get(i); @@ -8185,12 +8218,8 @@ public class WindowManagerService extends IWindowManager.Stub mNextAppTransitionType = ActivityOptions.ANIM_NONE; mNextAppTransitionPackage = null; mNextAppTransitionThumbnail = null; - if (mNextAppTransitionCallback != null) { - try { - mNextAppTransitionCallback.sendResult(null); - } catch (RemoteException e) { - } - } + scheduleAnimationCallback(mNextAppTransitionCallback); + mNextAppTransitionCallback = null; mOpeningApps.clear(); mClosingApps.clear(); @@ -9725,11 +9754,11 @@ public class WindowManagerService extends IWindowManager.Stub switch (mNextAppTransitionType) { case ActivityOptions.ANIM_CUSTOM: pw.print(" mNextAppTransitionPackage="); - pw.print(mNextAppTransitionPackage); - pw.print(" mNextAppTransitionEnter=0x"); + pw.println(mNextAppTransitionPackage); + pw.print(" mNextAppTransitionEnter=0x"); pw.print(Integer.toHexString(mNextAppTransitionEnter)); pw.print(" mNextAppTransitionExit=0x"); - pw.print(Integer.toHexString(mNextAppTransitionExit)); + pw.println(Integer.toHexString(mNextAppTransitionExit)); break; case ActivityOptions.ANIM_SCALE_UP: pw.print(" mNextAppTransitionStartX="); pw.print(mNextAppTransitionStartX); @@ -9744,11 +9773,17 @@ public class WindowManagerService extends IWindowManager.Stub case ActivityOptions.ANIM_THUMBNAIL_DELAYED: pw.print(" mNextAppTransitionThumbnail="); pw.print(mNextAppTransitionThumbnail); - pw.print(" mNextAppTransitionStartX="); pw.print(mNextAppTransitionStartX); - pw.print(" mNextAppTransitionStartY="); pw.println(mNextAppTransitionStartY); - pw.print(" mNextAppTransitionDelayed="); pw.println(mNextAppTransitionDelayed); + pw.print(" mNextAppTransitionStartX="); + pw.print(mNextAppTransitionStartX); + pw.print(" mNextAppTransitionStartY="); + pw.println(mNextAppTransitionStartY); + pw.print(" mNextAppTransitionDelayed="); pw.println(mNextAppTransitionDelayed); break; } + if (mNextAppTransitionCallback != null) { + pw.print(" mNextAppTransitionCallback="); + pw.println(mNextAppTransitionCallback); + } pw.print(" mStartingIconInTransition="); pw.print(mStartingIconInTransition); pw.print(", mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation); } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java index a4b2125549cf..8ab875fa6df2 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java @@ -226,8 +226,8 @@ public class BridgeWindowManager implements IWindowManager { } @Override - public void overridePendingAppTransition(String arg0, int arg1, int arg2) - throws RemoteException { + public void overridePendingAppTransition(String arg0, int arg1, int arg2, + IRemoteCallback startedCallback) throws RemoteException { // TODO Auto-generated method stub } |