Merge "Add UCE Service Down protected broadcast" into nyc-mr1-dev
diff --git a/core/java/android/animation/PropertyValuesHolder.java b/core/java/android/animation/PropertyValuesHolder.java
index 224823e..1dee925 100644
--- a/core/java/android/animation/PropertyValuesHolder.java
+++ b/core/java/android/animation/PropertyValuesHolder.java
@@ -1178,6 +1178,15 @@
}
@Override
+ public void setProperty(Property property) {
+ if (property instanceof IntProperty) {
+ mIntProperty = (IntProperty) property;
+ } else {
+ super.setProperty(property);
+ }
+ }
+
+ @Override
public void setIntValues(int... values) {
super.setIntValues(values);
mIntKeyframes = (Keyframes.IntKeyframes) mKeyframes;
@@ -1316,6 +1325,15 @@
}
@Override
+ public void setProperty(Property property) {
+ if (property instanceof FloatProperty) {
+ mFloatProperty = (FloatProperty) property;
+ } else {
+ super.setProperty(property);
+ }
+ }
+
+ @Override
public void setFloatValues(float... values) {
super.setFloatValues(values);
mFloatKeyframes = (Keyframes.FloatKeyframes) mKeyframes;
@@ -1516,7 +1534,7 @@
}
propertyMap.put(mPropertyName, mJniSetter);
}
- }
+ }
}
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index cb17be3..ec8b288 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -57,6 +57,7 @@
import android.media.AudioManager;
import android.media.session.MediaController;
import android.net.Uri;
+import android.os.BadParcelableException;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -5023,13 +5024,18 @@
@Nullable
public Uri getReferrer() {
Intent intent = getIntent();
- Uri referrer = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
- if (referrer != null) {
- return referrer;
- }
- String referrerName = intent.getStringExtra(Intent.EXTRA_REFERRER_NAME);
- if (referrerName != null) {
- return Uri.parse(referrerName);
+ try {
+ Uri referrer = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
+ if (referrer != null) {
+ return referrer;
+ }
+ String referrerName = intent.getStringExtra(Intent.EXTRA_REFERRER_NAME);
+ if (referrerName != null) {
+ return Uri.parse(referrerName);
+ }
+ } catch (BadParcelableException e) {
+ Log.w(TAG, "Cannot read referrer from intent;"
+ + " intent extras contain unknown custom Parcelable objects");
}
if (mReferrer != null) {
return new Uri.Builder().scheme("android-app").authority(mReferrer).build();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 2c2f6c1..0728bdf 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -16,6 +16,8 @@
package android.app;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.assist.AssistContent;
import android.app.assist.AssistStructure;
import android.app.backup.BackupAgent;
@@ -4578,20 +4580,37 @@
}
/**
+ * Creates a new Configuration only if override would modify base. Otherwise returns base.
+ * @param base The base configuration.
+ * @param override The update to apply to the base configuration. Can be null.
+ * @return A Configuration representing base with override applied.
+ */
+ private static Configuration createNewConfigAndUpdateIfNotNull(@NonNull Configuration base,
+ @Nullable Configuration override) {
+ if (override == null) {
+ return base;
+ }
+ Configuration newConfig = new Configuration(base);
+ newConfig.updateFrom(override);
+ return newConfig;
+ }
+
+ /**
* Decides whether to update an Activity's configuration and whether to tell the
* Activity/Component about it.
* @param cb The component callback to notify of configuration change.
* @param activityToken The Activity binder token for which this configuration change happened.
* If the change is global, this is null.
* @param newConfig The new configuration.
- * @param overrideConfig The override config that differentiates the Activity's configuration
+ * @param amOverrideConfig The override config that differentiates the Activity's configuration
* from the base global configuration.
+ * This is supplied by ActivityManager.
* @param reportToActivity Notify the Activity of the change.
*/
private void performConfigurationChanged(ComponentCallbacks2 cb,
IBinder activityToken,
Configuration newConfig,
- Configuration overrideConfig,
+ Configuration amOverrideConfig,
boolean reportToActivity) {
// Only for Activity objects, check that they actually call up to their
// superclass implementation. ComponentCallbacks2 is an interface, so
@@ -4605,7 +4624,6 @@
if ((activity == null) || (activity.mCurrentConfig == null)) {
shouldChangeConfig = true;
} else {
-
// If the new config is the same as the config this Activity
// is already running with then don't bother calling
// onConfigurationChanged
@@ -4615,34 +4633,36 @@
}
}
- if (DEBUG_CONFIGURATION) {
- Slog.v(TAG, "Config callback " + cb + ": shouldChangeConfig=" + shouldChangeConfig);
- }
-
if (shouldChangeConfig) {
+ // Propagate the configuration change to the Activity and ResourcesManager.
+
+ // ContextThemeWrappers may override the configuration for that context.
+ // We must check and apply any overrides defined.
+ Configuration contextThemeWrapperOverrideConfig = null;
+ if (cb instanceof ContextThemeWrapper) {
+ final ContextThemeWrapper contextThemeWrapper = (ContextThemeWrapper) cb;
+ contextThemeWrapperOverrideConfig = contextThemeWrapper.getOverrideConfiguration();
+ }
+
+ // We only update an Activity's configuration if this is not a global
+ // configuration change. This must also be done before the callback,
+ // or else we violate the contract that the new resources are available
+ // in {@link ComponentCallbacks2#onConfigurationChanged(Configuration)}.
if (activityToken != null) {
- // We only update an Activity's configuration if this is not a global
- // configuration change. This must also be done before the callback,
- // or else we violate the contract that the new resources are available
- // in {@link ComponentCallbacks2#onConfigurationChanged(Configuration)}.
- mResourcesManager.updateResourcesForActivity(activityToken, overrideConfig);
+ // Apply the ContextThemeWrapper override if necessary.
+ // NOTE: Make sure the configurations are not modified, as they are treated
+ // as immutable in many places.
+ final Configuration finalOverrideConfig = createNewConfigAndUpdateIfNotNull(
+ amOverrideConfig, contextThemeWrapperOverrideConfig);
+ mResourcesManager.updateResourcesForActivity(activityToken, finalOverrideConfig);
}
if (reportToActivity) {
- Configuration configToReport = newConfig;
-
- if (cb instanceof ContextThemeWrapper) {
- // ContextThemeWrappers may override the configuration for that context.
- // We must check and apply any overrides defined.
- ContextThemeWrapper contextThemeWrapper = (ContextThemeWrapper) cb;
- final Configuration localOverrideConfig =
- contextThemeWrapper.getOverrideConfiguration();
- if (localOverrideConfig != null) {
- configToReport = new Configuration(newConfig);
- configToReport.updateFrom(localOverrideConfig);
- }
- }
-
+ // Apply the ContextThemeWrapper override if necessary.
+ // NOTE: Make sure the configurations are not modified, as they are treated
+ // as immutable in many places.
+ final Configuration configToReport = createNewConfigAndUpdateIfNotNull(
+ newConfig, contextThemeWrapperOverrideConfig);
cb.onConfigurationChanged(configToReport);
}
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index ab4cbcf..0164fcd 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -793,12 +793,12 @@
return mOwningView != null && mOwningView.mAttachInfo != null;
}
- public void addAnimator(AnimatedVectorDrawable.VectorDrawableAnimatorRT animatorSet) {
+ public void registerVectorDrawableAnimator(
+ AnimatedVectorDrawable.VectorDrawableAnimatorRT animatorSet) {
if (mOwningView == null || mOwningView.mAttachInfo == null) {
throw new IllegalStateException("Cannot start this animator on a detached view!");
}
- nAddAnimator(mNativeRenderNode, animatorSet.getAnimatorNativePtr());
- mOwningView.mAttachInfo.mViewRootImpl.registerAnimatingRenderNode(this);
+ mOwningView.mAttachInfo.mViewRootImpl.registerVectorDrawableAnimator(animatorSet);
}
public void endAllAnimators() {
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index b4131b4..415e70c 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -51,6 +51,7 @@
private static native void nativeSetLayer(long nativeObject, int zorder);
private static native void nativeSetPosition(long nativeObject, float x, float y);
+ private static native void nativeSetPositionAppliesWithResize(long nativeObject);
private static native void nativeSetSize(long nativeObject, int w, int h);
private static native void nativeSetTransparentRegionHint(long nativeObject, Region region);
private static native void nativeSetAlpha(long nativeObject, float alpha);
@@ -407,6 +408,16 @@
nativeSetPosition(mNativeObject, x, y);
}
+ /**
+ * If the size changes in this transaction, position updates specified
+ * in this transaction will not complete until a buffer of the new size
+ * arrives.
+ */
+ public void setPositionAppliesWithResize() {
+ checkNotReleased();
+ nativeSetPositionAppliesWithResize(mNativeObject);
+ }
+
public void setSize(int w, int h) {
checkNotReleased();
nativeSetSize(mNativeObject, w, h);
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index e650d95..fcca739 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -23,6 +23,7 @@
import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.Rect;
+import android.graphics.drawable.AnimatedVectorDrawable;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -881,6 +882,12 @@
nRegisterAnimatingRenderNode(mRootNode.mNativeRenderNode, animator.mNativeRenderNode);
}
+ void registerVectorDrawableAnimator(
+ AnimatedVectorDrawable.VectorDrawableAnimatorRT animator) {
+ nRegisterVectorDrawableAnimator(mRootNode.mNativeRenderNode,
+ animator.getAnimatorNativePtr());
+ }
+
public void serializeDisplayListTree() {
nSerializeDisplayListTree(mNativeProxy);
}
@@ -992,6 +999,7 @@
private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size);
private static native void nDestroy(long nativeProxy, long rootRenderNode);
private static native void nRegisterAnimatingRenderNode(long rootRenderNode, long animatingNode);
+ private static native void nRegisterVectorDrawableAnimator(long rootRenderNode, long animator);
private static native void nInvokeFunctor(long functor, boolean waitForCompletion);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 4742818..06c8e01 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -42,6 +42,7 @@
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.Region;
+import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
@@ -824,6 +825,13 @@
}
}
+ public void registerVectorDrawableAnimator(
+ AnimatedVectorDrawable.VectorDrawableAnimatorRT animator) {
+ if (mAttachInfo.mHardwareRenderer != null) {
+ mAttachInfo.mHardwareRenderer.registerVectorDrawableAnimator(animator);
+ }
+ }
+
private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
mAttachInfo.mHardwareAccelerated = false;
mAttachInfo.mHardwareAccelerationRequested = false;
diff --git a/core/java/com/android/internal/policy/BackdropFrameRenderer.java b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
index 28281b3c..8addffb0 100644
--- a/core/java/com/android/internal/policy/BackdropFrameRenderer.java
+++ b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
@@ -370,6 +370,8 @@
systemInsets.bottom);
final int rightInset = DecorView.getColorViewRightInset(stableInsets.right,
systemInsets.right);
+ final int leftInset = DecorView.getColorViewLeftInset(stableInsets.left,
+ systemInsets.left);
if (mStatusBarColor != null) {
mStatusBarColor.setBounds(0, 0, left + width, topInset);
mStatusBarColor.draw(canvas);
@@ -379,9 +381,11 @@
// don't want the navigation bar background be moving around when resizing in docked mode.
// However, we need it for the transitions into/out of docked mode.
if (mNavigationBarColor != null && fullscreen) {
- final int size = DecorView.getNavBarSize(bottomInset, rightInset);
+ final int size = DecorView.getNavBarSize(bottomInset, rightInset, leftInset);
if (DecorView.isNavBarToRightEdge(bottomInset, rightInset)) {
mNavigationBarColor.setBounds(width - size, 0, width, height);
+ } else if (DecorView.isNavBarToLeftEdge(bottomInset, rightInset)) {
+ mNavigationBarColor.setBounds(0, 0, size, height);
} else {
mNavigationBarColor.setBounds(0, height - size, width, height);
}
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 7e38d9b..1099ef7 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -97,7 +97,6 @@
import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -162,13 +161,13 @@
private final ColorViewState mStatusColorViewState = new ColorViewState(
SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS,
- Gravity.TOP, Gravity.LEFT,
+ Gravity.TOP, Gravity.LEFT, Gravity.RIGHT,
Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME,
com.android.internal.R.id.statusBarBackground,
FLAG_FULLSCREEN);
private final ColorViewState mNavigationColorViewState = new ColorViewState(
SYSTEM_UI_FLAG_HIDE_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION,
- Gravity.BOTTOM, Gravity.RIGHT,
+ Gravity.BOTTOM, Gravity.RIGHT, Gravity.LEFT,
Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME,
com.android.internal.R.id.navigationBarBackground,
0 /* hideWindowFlag */);
@@ -184,9 +183,11 @@
private int mLastTopInset = 0;
private int mLastBottomInset = 0;
private int mLastRightInset = 0;
+ private int mLastLeftInset = 0;
private boolean mLastHasTopStableInset = false;
private boolean mLastHasBottomStableInset = false;
private boolean mLastHasRightStableInset = false;
+ private boolean mLastHasLeftStableInset = false;
private int mLastWindowFlags = 0;
private boolean mLastShouldAlwaysConsumeNavBar = false;
@@ -991,12 +992,21 @@
return Math.min(stableRight, systemRight);
}
+ static int getColorViewLeftInset(int stableLeft, int systemLeft) {
+ return Math.min(stableLeft, systemLeft);
+ }
+
static boolean isNavBarToRightEdge(int bottomInset, int rightInset) {
return bottomInset == 0 && rightInset > 0;
}
- static int getNavBarSize(int bottomInset, int rightInset) {
- return isNavBarToRightEdge(bottomInset, rightInset) ? rightInset : bottomInset;
+ static boolean isNavBarToLeftEdge(int bottomInset, int leftInset) {
+ return bottomInset == 0 && leftInset > 0;
+ }
+
+ static int getNavBarSize(int bottomInset, int rightInset, int leftInset) {
+ return isNavBarToRightEdge(bottomInset, rightInset) ? rightInset
+ : isNavBarToLeftEdge(bottomInset, leftInset) ? leftInset : bottomInset;
}
WindowInsets updateColorViews(WindowInsets insets, boolean animate) {
@@ -1016,6 +1026,8 @@
insets.getSystemWindowInsetBottom());
mLastRightInset = getColorViewRightInset(insets.getStableInsetRight(),
insets.getSystemWindowInsetRight());
+ mLastLeftInset = getColorViewRightInset(insets.getStableInsetLeft(),
+ insets.getSystemWindowInsetLeft());
// Don't animate if the presence of stable insets has changed, because that
// indicates that the window was either just added and received them for the
@@ -1031,21 +1043,32 @@
boolean hasRightStableInset = insets.getStableInsetRight() != 0;
disallowAnimate |= (hasRightStableInset != mLastHasRightStableInset);
mLastHasRightStableInset = hasRightStableInset;
+
+ boolean hasLeftStableInset = insets.getStableInsetLeft() != 0;
+ disallowAnimate |= (hasLeftStableInset != mLastHasLeftStableInset);
+ mLastHasLeftStableInset = hasLeftStableInset;
+
mLastShouldAlwaysConsumeNavBar = insets.shouldAlwaysConsumeNavBar();
}
boolean navBarToRightEdge = isNavBarToRightEdge(mLastBottomInset, mLastRightInset);
- int navBarSize = getNavBarSize(mLastBottomInset, mLastRightInset);
+ boolean navBarToLeftEdge = isNavBarToLeftEdge(mLastBottomInset, mLastLeftInset);
+ int navBarSize = getNavBarSize(mLastBottomInset, mLastRightInset, mLastLeftInset);
updateColorViewInt(mNavigationColorViewState, sysUiVisibility,
- mWindow.mNavigationBarColor, navBarSize, navBarToRightEdge,
- 0 /* rightInset */, animate && !disallowAnimate, false /* force */);
+ mWindow.mNavigationBarColor, navBarSize, navBarToRightEdge || navBarToLeftEdge,
+ navBarToLeftEdge,
+ 0 /* sideInset */, animate && !disallowAnimate, false /* force */);
boolean statusBarNeedsRightInset = navBarToRightEdge
&& mNavigationColorViewState.present;
- int statusBarRightInset = statusBarNeedsRightInset ? mLastRightInset : 0;
+ boolean statusBarNeedsLeftInset = navBarToLeftEdge
+ && mNavigationColorViewState.present;
+ int statusBarSideInset = statusBarNeedsRightInset ? mLastRightInset
+ : statusBarNeedsLeftInset ? mLastLeftInset : 0;
updateColorViewInt(mStatusColorViewState, sysUiVisibility,
calculateStatusBarColor(), mLastTopInset,
- false /* matchVertical */, statusBarRightInset, animate && !disallowAnimate,
+ false /* matchVertical */, statusBarNeedsLeftInset, statusBarSideInset,
+ animate && !disallowAnimate,
mForceWindowDrawsStatusBarBackground);
}
@@ -1070,15 +1093,17 @@
int consumedTop = consumingStatusBar ? mLastTopInset : 0;
int consumedRight = consumingNavBar ? mLastRightInset : 0;
int consumedBottom = consumingNavBar ? mLastBottomInset : 0;
+ int consumedLeft = consumingNavBar ? mLastLeftInset : 0;
if (mContentRoot != null
&& mContentRoot.getLayoutParams() instanceof MarginLayoutParams) {
MarginLayoutParams lp = (MarginLayoutParams) mContentRoot.getLayoutParams();
if (lp.topMargin != consumedTop || lp.rightMargin != consumedRight
- || lp.bottomMargin != consumedBottom) {
+ || lp.bottomMargin != consumedBottom || lp.leftMargin != consumedLeft) {
lp.topMargin = consumedTop;
lp.rightMargin = consumedRight;
lp.bottomMargin = consumedBottom;
+ lp.leftMargin = consumedLeft;
mContentRoot.setLayoutParams(lp);
if (insets == null) {
@@ -1089,7 +1114,7 @@
}
if (insets != null) {
insets = insets.replaceSystemWindowInsets(
- insets.getSystemWindowInsetLeft(),
+ insets.getSystemWindowInsetLeft() - consumedLeft,
insets.getSystemWindowInsetTop() - consumedTop,
insets.getSystemWindowInsetRight() - consumedRight,
insets.getSystemWindowInsetBottom() - consumedBottom);
@@ -1126,11 +1151,12 @@
* @param size the current size in the non-parent-matching dimension.
* @param verticalBar if true the view is attached to a vertical edge, otherwise to a
* horizontal edge,
- * @param rightMargin rightMargin for the color view.
+ * @param sideMargin sideMargin for the color view.
* @param animate if true, the change will be animated.
*/
private void updateColorViewInt(final ColorViewState state, int sysUiVis, int color,
- int size, boolean verticalBar, int rightMargin, boolean animate, boolean force) {
+ int size, boolean verticalBar, boolean seascape, int sideMargin,
+ boolean animate, boolean force) {
state.present = (sysUiVis & state.systemUiHideFlag) == 0
&& (mWindow.getAttributes().flags & state.hideWindowFlag) == 0
&& ((mWindow.getAttributes().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
@@ -1145,7 +1171,9 @@
int resolvedHeight = verticalBar ? LayoutParams.MATCH_PARENT : size;
int resolvedWidth = verticalBar ? size : LayoutParams.MATCH_PARENT;
- int resolvedGravity = verticalBar ? state.horizontalGravity : state.verticalGravity;
+ int resolvedGravity = verticalBar
+ ? (seascape ? state.seascapeGravity : state.horizontalGravity)
+ : state.verticalGravity;
if (view == null) {
if (showView) {
@@ -1159,7 +1187,11 @@
LayoutParams lp = new LayoutParams(resolvedWidth, resolvedHeight,
resolvedGravity);
- lp.rightMargin = rightMargin;
+ if (seascape) {
+ lp.leftMargin = sideMargin;
+ } else {
+ lp.rightMargin = sideMargin;
+ }
addView(view, lp);
updateColorViewTranslations();
}
@@ -1168,12 +1200,16 @@
visibilityChanged = state.targetVisibility != vis;
state.targetVisibility = vis;
LayoutParams lp = (LayoutParams) view.getLayoutParams();
+ int rightMargin = seascape ? 0 : sideMargin;
+ int leftMargin = seascape ? sideMargin : 0;
if (lp.height != resolvedHeight || lp.width != resolvedWidth
- || lp.gravity != resolvedGravity || lp.rightMargin != rightMargin) {
+ || lp.gravity != resolvedGravity || lp.rightMargin != rightMargin
+ || lp.leftMargin != leftMargin) {
lp.height = resolvedHeight;
lp.width = resolvedWidth;
lp.gravity = resolvedGravity;
lp.rightMargin = rightMargin;
+ lp.leftMargin = leftMargin;
view.setLayoutParams(lp);
}
if (showView) {
@@ -2210,17 +2246,19 @@
final int translucentFlag;
final int verticalGravity;
final int horizontalGravity;
+ final int seascapeGravity;
final String transitionName;
final int hideWindowFlag;
ColorViewState(int systemUiHideFlag,
int translucentFlag, int verticalGravity, int horizontalGravity,
- String transitionName, int id, int hideWindowFlag) {
+ int seascapeGravity, String transitionName, int id, int hideWindowFlag) {
this.id = id;
this.systemUiHideFlag = systemUiHideFlag;
this.translucentFlag = translucentFlag;
this.verticalGravity = verticalGravity;
this.horizontalGravity = horizontalGravity;
+ this.seascapeGravity = seascapeGravity;
this.transitionName = transitionName;
this.hideWindowFlag = hideWindowFlag;
}
diff --git a/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp b/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp
index 4b2a72d..0ba88e6 100644
--- a/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp
+++ b/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp
@@ -95,6 +95,12 @@
return reinterpret_cast<jlong>(animatorSet);
}
+static void setVectorDrawableTarget(JNIEnv*, jobject,jlong animatorPtr, jlong vectorDrawablePtr) {
+ VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(vectorDrawablePtr);
+ PropertyValuesAnimatorSet* set = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorPtr);
+ set->setVectorDrawable(tree);
+}
+
static jlong createGroupPropertyHolder(JNIEnv*, jobject, jlong nativePtr, jint propertyId,
jfloat startValue, jfloat endValue) {
VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(nativePtr);
@@ -168,6 +174,7 @@
static const JNINativeMethod gMethods[] = {
{"nCreateAnimatorSet", "()J", (void*)createAnimatorSet},
+ {"nSetVectorDrawableTarget", "(JJ)V", (void*)setVectorDrawableTarget},
{"nAddAnimator", "(JJJJJI)V", (void*)addAnimator},
{"nCreateGroupPropertyHolder", "!(JIFF)J", (void*)createGroupPropertyHolder},
{"nCreatePathDataPropertyHolder", "!(JJJ)J", (void*)createPathDataPropertyHolder},
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index a9ed9dc..ff75677 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -248,6 +248,15 @@
}
}
+static void nativeSetPositionAppliesWithResize(JNIEnv* env, jclass clazz,
+ jlong nativeObject) {
+ SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+ status_t err = ctrl->setPositionAppliesWithResize();
+ if (err < 0 && err != NO_INIT) {
+ doThrowIAE(env);
+ }
+}
+
static void nativeSetSize(JNIEnv* env, jclass clazz, jlong nativeObject, jint w, jint h) {
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
status_t err = ctrl->setSize(w, h);
@@ -658,6 +667,8 @@
(void*)nativeSetLayer },
{"nativeSetPosition", "(JFF)V",
(void*)nativeSetPosition },
+ {"nativeSetPositionAppliesWithResize", "(J)V",
+ (void*)nativeSetPositionAppliesWithResize },
{"nativeSetSize", "(JII)V",
(void*)nativeSetSize },
{"nativeSetTransparentRegionHint", "(JLandroid/graphics/Region;)V",
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 5b4bfe9..212bf57 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -32,6 +32,7 @@
#include <utils/Looper.h>
#include <utils/RefBase.h>
#include <utils/StrongPointer.h>
+#include <utils/Timers.h>
#include <android_runtime/android_view_Surface.h>
#include <system/window.h>
@@ -44,6 +45,7 @@
#include <FrameMetricsObserver.h>
#include <IContextFactory.h>
#include <JankTracker.h>
+#include <PropertyValuesAnimatorSet.h>
#include <RenderNode.h>
#include <renderthread/CanvasContext.h>
#include <renderthread/RenderProxy.h>
@@ -122,6 +124,31 @@
std::vector<OnFinishedEvent> mOnFinishedEvents;
};
+class FinishAndInvokeListener : public MessageHandler {
+public:
+ explicit FinishAndInvokeListener(PropertyValuesAnimatorSet* anim)
+ : mAnimator(anim) {
+ mListener = anim->getOneShotListener();
+ mRequestId = anim->getRequestId();
+ }
+
+ virtual void handleMessage(const Message& message) {
+ if (mAnimator->getRequestId() == mRequestId) {
+ // Request Id has not changed, meaning there's no animation lifecyle change since the
+ // message is posted, so go ahead and call finish to make sure the PlayState is properly
+ // updated. This is needed because before the next frame comes in from UI thread to
+ // trigger an animation update, there could be reverse/cancel etc. So we need to update
+ // the playstate in time to ensure all the subsequent events get chained properly.
+ mAnimator->end();
+ }
+ mListener->onAnimationFinished(nullptr);
+ }
+private:
+ sp<PropertyValuesAnimatorSet> mAnimator;
+ sp<AnimationListener> mListener;
+ uint32_t mRequestId;
+};
+
class RenderingException : public MessageHandler {
public:
RenderingException(JavaVM* vm, const std::string& message)
@@ -160,6 +187,15 @@
virtual void prepareTree(TreeInfo& info) override {
info.errorHandler = this;
+
+ for (auto& anim : mVectorDrawableAnimators) {
+ // Assume that the property change in VD from the animators will not be consumed. Mark
+ // otherwise if the VDs are found in the display list tree. For VDs that are not in
+ // the display list tree, we stop providing animation pulses by 1) removing them from
+ // the animation list, 2) post a delayed message to end them at end time so their
+ // listeners can receive the corresponding callbacks.
+ anim->getVectorDrawable()->setPropertyChangeWillBeConsumed(false);
+ }
// TODO: This is hacky
info.windowInsetLeft = -stagingProperties().getLeft();
info.windowInsetTop = -stagingProperties().getTop();
@@ -169,16 +205,46 @@
info.windowInsetLeft = 0;
info.windowInsetTop = 0;
info.errorHandler = nullptr;
+
+ for (auto it = mVectorDrawableAnimators.begin(); it != mVectorDrawableAnimators.end();) {
+ if (!(*it)->getVectorDrawable()->getPropertyChangeWillBeConsumed()) {
+ // Vector Drawable is not in the display list, we should remove this animator from
+ // the list and post a delayed message to end the animator.
+ detachVectorDrawableAnimator(it->get());
+ it = mVectorDrawableAnimators.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ info.out.hasAnimations |= !mVectorDrawableAnimators.empty();
}
void sendMessage(const sp<MessageHandler>& handler) {
mLooper->sendMessage(handler, 0);
}
+ void sendMessageDelayed(const sp<MessageHandler>& handler, nsecs_t delayInMs) {
+ mLooper->sendMessageDelayed(ms2ns(delayInMs), handler, 0);
+ }
+
void attachAnimatingNode(RenderNode* animatingNode) {
mPendingAnimatingRenderNodes.push_back(animatingNode);
}
+ void attachPendingVectorDrawableAnimators() {
+ mVectorDrawableAnimators.insert(mPendingVectorDrawableAnimators.begin(),
+ mPendingVectorDrawableAnimators.end());
+ mPendingVectorDrawableAnimators.clear();
+ }
+
+ void detachAnimators() {
+ // Remove animators from the list and post a delayed message in future to end the animator
+ for (auto& anim : mVectorDrawableAnimators) {
+ detachVectorDrawableAnimator(anim.get());
+ }
+ mVectorDrawableAnimators.clear();
+ }
+
void doAttachAnimatingNodes(AnimationContext* context) {
for (size_t i = 0; i < mPendingAnimatingRenderNodes.size(); i++) {
RenderNode* node = mPendingAnimatingRenderNodes[i].get();
@@ -187,17 +253,57 @@
mPendingAnimatingRenderNodes.clear();
}
+ void runVectorDrawableAnimators(AnimationContext* context) {
+ for (auto it = mVectorDrawableAnimators.begin(); it != mVectorDrawableAnimators.end();) {
+ (*it)->pushStaging(*context);
+ if ((*it)->animate(*context)) {
+ it = mVectorDrawableAnimators.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ }
+
void destroy() {
for (auto& renderNode : mPendingAnimatingRenderNodes) {
renderNode->animators().endAllStagingAnimators();
}
mPendingAnimatingRenderNodes.clear();
+ mPendingVectorDrawableAnimators.clear();
+ }
+
+ void addVectorDrawableAnimator(PropertyValuesAnimatorSet* anim) {
+ mPendingVectorDrawableAnimators.insert(anim);
}
private:
sp<Looper> mLooper;
JavaVM* mVm;
std::vector< sp<RenderNode> > mPendingAnimatingRenderNodes;
+ std::set< sp<PropertyValuesAnimatorSet> > mPendingVectorDrawableAnimators;
+ std::set< sp<PropertyValuesAnimatorSet> > mVectorDrawableAnimators;
+ void detachVectorDrawableAnimator(PropertyValuesAnimatorSet* anim) {
+ if (anim->isInfinite() || !anim->isRunning()) {
+ // Do not need to post anything if the animation is infinite (i.e. no meaningful
+ // end listener action), or if the animation has already ended.
+ return;
+ }
+ nsecs_t remainingTimeInMs = anim->getRemainingPlayTime();
+ // Post a delayed onFinished event that is scheduled to be handled when the animator ends.
+ if (anim->getOneShotListener()) {
+ // VectorDrawable's oneshot listener is updated when there are user triggered animation
+ // lifecycle changes, such as start(), end(), etc. By using checking and clearing
+ // one shot listener, we ensure the same end listener event gets posted only once.
+ // Therefore no duplicates. Another benefit of using one shot listener is that no
+ // removal is necessary: the end time of animation will not change unless triggered by
+ // user events, in which case the already posted listener's id will become stale, and
+ // the onFinished callback will then be ignored.
+ sp<FinishAndInvokeListener> message
+ = new FinishAndInvokeListener(anim);
+ sendMessageDelayed(message, remainingTimeInMs);
+ anim->clearOneShotListener();
+ }
+ }
};
class AnimationContextBridge : public AnimationContext {
@@ -213,8 +319,16 @@
virtual void startFrame(TreeInfo::TraversalMode mode) {
if (mode == TreeInfo::MODE_FULL) {
mRootNode->doAttachAnimatingNodes(this);
+ mRootNode->attachPendingVectorDrawableAnimators();
}
AnimationContext::startFrame(mode);
+ // Run VectorDrawable animators in the beginning of the frame instead of during prepareTree,
+ // because one VD can be in multiple render nodes' display list. So it's more simple to
+ // run them all at once before prepareTree than running them or checking whether they have
+ // already ran in each RenderNode. Note that these animators don't damage the RenderNodes.
+ // The damaging is done in prepareTree as needed after checking whether a VD has been
+ // modified.
+ mRootNode->runVectorDrawableAnimators(this);
}
// Runs any animations still left in mCurrentFrameAnimations
@@ -223,6 +337,10 @@
postOnFinishedEvents();
}
+ virtual void detachAnimators() override {
+ mRootNode->detachAnimators();
+ }
+
virtual void callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener) {
OnFinishedEvent event(animator, listener);
mOnFinishedEvents.push_back(event);
@@ -230,6 +348,7 @@
virtual void destroy() {
AnimationContext::destroy();
+ detachAnimators();
postOnFinishedEvents();
}
@@ -528,6 +647,13 @@
rootRenderNode->attachAnimatingNode(animatingNode);
}
+static void android_view_ThreadedRenderer_registerVectorDrawableAnimator(JNIEnv* env, jobject clazz,
+ jlong rootNodePtr, jlong animatorPtr) {
+ RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootNodePtr);
+ PropertyValuesAnimatorSet* animator = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorPtr);
+ rootRenderNode->addVectorDrawableAnimator(animator);
+}
+
static void android_view_ThreadedRenderer_invokeFunctor(JNIEnv* env, jobject clazz,
jlong functorPtr, jboolean waitForCompletion) {
Functor* functor = reinterpret_cast<Functor*>(functorPtr);
@@ -739,6 +865,7 @@
{ "nSyncAndDrawFrame", "(J[JI)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
{ "nDestroy", "(JJ)V", (void*) android_view_ThreadedRenderer_destroy },
{ "nRegisterAnimatingRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_registerAnimatingRenderNode },
+ { "nRegisterVectorDrawableAnimator", "(JJ)V", (void*) android_view_ThreadedRenderer_registerVectorDrawableAnimator },
{ "nInvokeFunctor", "(JZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
{ "nCreateTextureLayer", "(J)J", (void*) android_view_ThreadedRenderer_createTextureLayer },
{ "nBuildLayer", "(JJ)V", (void*) android_view_ThreadedRenderer_buildLayer },
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index 6762bea..44d95d2 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -46,6 +46,7 @@
import android.util.Log;
import android.util.LongArray;
import android.util.PathParser;
+import android.util.Property;
import android.util.TimeUtils;
import android.view.Choreographer;
import android.view.DisplayListCanvas;
@@ -157,7 +158,7 @@
private static final boolean DBG_ANIMATION_VECTOR_DRAWABLE = false;
/** Local, mutable animator set. */
- private VectorDrawableAnimator mAnimatorSet = new VectorDrawableAnimatorUI(this);
+ private VectorDrawableAnimator mAnimatorSet;
/**
* The resources against which this drawable was created. Used to attempt
@@ -182,6 +183,7 @@
private AnimatedVectorDrawable(AnimatedVectorDrawableState state, Resources res) {
mAnimatedVectorState = new AnimatedVectorDrawableState(state, mCallback, res);
+ mAnimatorSet = new VectorDrawableAnimatorRT(this);
mRes = res;
}
@@ -390,9 +392,11 @@
R.styleable.AnimatedVectorDrawableTarget_animation, 0);
if (animResId != 0) {
if (theme != null) {
- final Animator objectAnimator = AnimatorInflater.loadAnimator(
+ // The animator here could be ObjectAnimator or AnimatorSet.
+ final Animator animator = AnimatorInflater.loadAnimator(
res, theme, animResId, pathErrorScale);
- state.addTargetAnimator(target, objectAnimator);
+ updateAnimatorProperty(animator, target, state.mVectorDrawable);
+ state.addTargetAnimator(target, animator);
} else {
// The animation may be theme-dependent. As a
// workaround until Animator has full support for
@@ -414,6 +418,36 @@
mRes = state.mPendingAnims == null ? null : res;
}
+ private static void updateAnimatorProperty(Animator animator, String targetName,
+ VectorDrawable vectorDrawable) {
+ if (animator instanceof ObjectAnimator) {
+ // Change the property of the Animator from using reflection based on the property
+ // name to a Property object that wraps the setter and getter for modifying that
+ // specific property for a given object. By replacing the reflection with a direct call,
+ // we can largely reduce the time it takes for a animator to modify a VD property.
+ PropertyValuesHolder[] holders = ((ObjectAnimator) animator).getValues();
+ for (int i = 0; i < holders.length; i++) {
+ PropertyValuesHolder pvh = holders[i];
+ String propertyName = pvh.getPropertyName();
+ Object targetNameObj = vectorDrawable.getTargetByName(targetName);
+ Property property = null;
+ if (targetNameObj instanceof VectorDrawable.VObject) {
+ property = ((VectorDrawable.VObject) targetNameObj).getProperty(propertyName);
+ } else if (targetNameObj instanceof VectorDrawable.VectorDrawableState) {
+ property = ((VectorDrawable.VectorDrawableState) targetNameObj)
+ .getProperty(propertyName);
+ }
+ if (property != null) {
+ pvh.setProperty(property);
+ }
+ }
+ } else if (animator instanceof AnimatorSet) {
+ for (Animator anim : ((AnimatorSet) animator).getChildAnimations()) {
+ updateAnimatorProperty(anim, targetName, vectorDrawable);
+ }
+ }
+ }
+
/**
* Force to animate on UI thread.
* @hide
@@ -616,8 +650,9 @@
for (int i = 0, count = pendingAnims.size(); i < count; i++) {
final PendingAnimator pendingAnimator = pendingAnims.get(i);
- final Animator objectAnimator = pendingAnimator.newInstance(res, t);
- addTargetAnimator(pendingAnimator.target, objectAnimator);
+ final Animator animator = pendingAnimator.newInstance(res, t);
+ updateAnimatorProperty(animator, pendingAnimator.target, mVectorDrawable);
+ addTargetAnimator(pendingAnimator.target, animator);
}
}
}
@@ -999,7 +1034,7 @@
private WeakReference<RenderNode> mLastSeenTarget = null;
private int mLastListenerId = 0;
private final IntArray mPendingAnimationActions = new IntArray();
- private final Drawable mDrawable;
+ private final AnimatedVectorDrawable mDrawable;
VectorDrawableAnimatorRT(AnimatedVectorDrawable drawable) {
mDrawable = drawable;
@@ -1018,6 +1053,9 @@
}
mShouldIgnoreInvalidAnim = shouldIgnoreInvalidAnimation();
parseAnimatorSet(set, 0);
+ long vectorDrawableTreePtr = mDrawable.mAnimatedVectorState.mVectorDrawable
+ .getNativeTree();
+ nSetVectorDrawableTarget(mSetPtr, vectorDrawableTreePtr);
mInitialized = true;
mIsInfinite = set.getTotalDuration() == Animator.DURATION_INFINITE;
@@ -1254,16 +1292,19 @@
* to the last seen RenderNode target and start right away.
*/
protected void recordLastSeenTarget(DisplayListCanvas canvas) {
- mLastSeenTarget = new WeakReference<RenderNode>(
- RenderNodeAnimatorSetHelper.getTarget(canvas));
- if (mPendingAnimationActions.size() > 0 && useLastSeenTarget()) {
- if (DBG_ANIMATION_VECTOR_DRAWABLE) {
- Log.d(LOGTAG, "Target is set in the next frame");
+ final RenderNode node = RenderNodeAnimatorSetHelper.getTarget(canvas);
+ mLastSeenTarget = new WeakReference<RenderNode>(node);
+ // Add the animator to the list of animators on every draw
+ if (mInitialized || mPendingAnimationActions.size() > 0) {
+ if (useTarget(node)) {
+ if (DBG_ANIMATION_VECTOR_DRAWABLE) {
+ Log.d(LOGTAG, "Target is set in the next frame");
+ }
+ for (int i = 0; i < mPendingAnimationActions.size(); i++) {
+ handlePendingAction(mPendingAnimationActions.get(i));
+ }
+ mPendingAnimationActions.clear();
}
- for (int i = 0; i < mPendingAnimationActions.size(); i++) {
- handlePendingAction(mPendingAnimationActions.get(i));
- }
- mPendingAnimationActions.clear();
}
}
@@ -1285,10 +1326,15 @@
private boolean useLastSeenTarget() {
if (mLastSeenTarget != null) {
final RenderNode target = mLastSeenTarget.get();
- if (target != null && target.isAttached()) {
- target.addAnimator(this);
- return true;
- }
+ return useTarget(target);
+ }
+ return false;
+ }
+
+ private boolean useTarget(RenderNode target) {
+ if (target != null && target.isAttached()) {
+ target.registerVectorDrawableAnimator(this);
+ return true;
}
return false;
}
@@ -1483,6 +1529,7 @@
}
private static native long nCreateAnimatorSet();
+ private static native void nSetVectorDrawableTarget(long animatorPtr, long vectorDrawablePtr);
private static native void nAddAnimator(long setPtr, long propertyValuesHolder,
long nativeInterpolator, long startDelay, long duration, int repeatCount);
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index f5592fa..a8c8737 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -34,9 +34,12 @@
import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
+import android.util.FloatProperty;
+import android.util.IntProperty;
import android.util.LayoutDirection;
import android.util.Log;
import android.util.PathParser;
+import android.util.Property;
import android.util.Xml;
import com.android.internal.R;
@@ -758,6 +761,13 @@
return mVectorState.mAutoMirrored;
}
+ /**
+ * @hide
+ */
+ public long getNativeTree() {
+ return mVectorState.getNativeRenderer();
+ }
+
static class VectorDrawableState extends ConstantState {
// Variables below need to be copied (deep copy if applicable) for mutation.
int[] mThemeAttrs;
@@ -790,6 +800,26 @@
int mLastSWCachePixelCount = 0;
int mLastHWCachePixelCount = 0;
+ final static Property<VectorDrawableState, Float> ALPHA =
+ new FloatProperty<VectorDrawableState>("alpha") {
+ @Override
+ public void setValue(VectorDrawableState state, float value) {
+ state.setAlpha(value);
+ }
+
+ @Override
+ public Float get(VectorDrawableState state) {
+ return state.getAlpha();
+ }
+ };
+
+ Property getProperty(String propertyName) {
+ if (ALPHA.getName().equals(propertyName)) {
+ return ALPHA;
+ }
+ return null;
+ }
+
// This tracks the total native allocation for all the nodes.
private int mAllocationOfAllNodes = 0;
@@ -967,7 +997,7 @@
}
static class VGroup extends VObject {
- private static final int ROTATE_INDEX = 0;
+ private static final int ROTATION_INDEX = 0;
private static final int PIVOT_X_INDEX = 1;
private static final int PIVOT_Y_INDEX = 2;
private static final int SCALE_X_INDEX = 3;
@@ -978,7 +1008,7 @@
private static final int NATIVE_ALLOCATION_SIZE = 100;
- private static final HashMap<String, Integer> sPropertyMap =
+ private static final HashMap<String, Integer> sPropertyIndexMap =
new HashMap<String, Integer>() {
{
put("translateX", TRANSLATE_X_INDEX);
@@ -987,19 +1017,123 @@
put("scaleY", SCALE_Y_INDEX);
put("pivotX", PIVOT_X_INDEX);
put("pivotY", PIVOT_Y_INDEX);
- put("rotation", ROTATE_INDEX);
+ put("rotation", ROTATION_INDEX);
}
};
static int getPropertyIndex(String propertyName) {
- if (sPropertyMap.containsKey(propertyName)) {
- return sPropertyMap.get(propertyName);
+ if (sPropertyIndexMap.containsKey(propertyName)) {
+ return sPropertyIndexMap.get(propertyName);
} else {
// property not found
return -1;
}
}
+ // Below are the Properties that wrap the setters to avoid reflection overhead in animations
+ private static final Property<VGroup, Float> TRANSLATE_X =
+ new FloatProperty<VGroup> ("translateX") {
+ @Override
+ public void setValue(VGroup object, float value) {
+ object.setTranslateX(value);
+ }
+
+ @Override
+ public Float get(VGroup object) {
+ return object.getTranslateX();
+ }
+ };
+
+ private static final Property<VGroup, Float> TRANSLATE_Y =
+ new FloatProperty<VGroup> ("translateY") {
+ @Override
+ public void setValue(VGroup object, float value) {
+ object.setTranslateY(value);
+ }
+
+ @Override
+ public Float get(VGroup object) {
+ return object.getTranslateY();
+ }
+ };
+
+ private static final Property<VGroup, Float> SCALE_X =
+ new FloatProperty<VGroup> ("scaleX") {
+ @Override
+ public void setValue(VGroup object, float value) {
+ object.setScaleX(value);
+ }
+
+ @Override
+ public Float get(VGroup object) {
+ return object.getScaleX();
+ }
+ };
+
+ private static final Property<VGroup, Float> SCALE_Y =
+ new FloatProperty<VGroup> ("scaleY") {
+ @Override
+ public void setValue(VGroup object, float value) {
+ object.setScaleY(value);
+ }
+
+ @Override
+ public Float get(VGroup object) {
+ return object.getScaleY();
+ }
+ };
+
+ private static final Property<VGroup, Float> PIVOT_X =
+ new FloatProperty<VGroup> ("pivotX") {
+ @Override
+ public void setValue(VGroup object, float value) {
+ object.setPivotX(value);
+ }
+
+ @Override
+ public Float get(VGroup object) {
+ return object.getPivotX();
+ }
+ };
+
+ private static final Property<VGroup, Float> PIVOT_Y =
+ new FloatProperty<VGroup> ("pivotY") {
+ @Override
+ public void setValue(VGroup object, float value) {
+ object.setPivotY(value);
+ }
+
+ @Override
+ public Float get(VGroup object) {
+ return object.getPivotY();
+ }
+ };
+
+ private static final Property<VGroup, Float> ROTATION =
+ new FloatProperty<VGroup> ("rotation") {
+ @Override
+ public void setValue(VGroup object, float value) {
+ object.setRotation(value);
+ }
+
+ @Override
+ public Float get(VGroup object) {
+ return object.getRotation();
+ }
+ };
+
+ private static final HashMap<String, Property> sPropertyMap =
+ new HashMap<String, Property>() {
+ {
+ put("translateX", TRANSLATE_X);
+ put("translateY", TRANSLATE_Y);
+ put("scaleX", SCALE_X);
+ put("scaleY", SCALE_Y);
+ put("pivotX", PIVOT_X);
+ put("pivotY", PIVOT_Y);
+ put("rotation", ROTATION);
+ }
+ };
// Temp array to store transform values obtained from native.
private float[] mTransform;
/////////////////////////////////////////////////////
@@ -1055,6 +1189,15 @@
mNativePtr = nCreateGroup();
}
+ Property getProperty(String propertyName) {
+ if (sPropertyMap.containsKey(propertyName)) {
+ return sPropertyMap.get(propertyName);
+ } else {
+ // property not found
+ return null;
+ }
+ }
+
public String getGroupName() {
return mGroupName;
}
@@ -1102,7 +1245,7 @@
throw new RuntimeException("Error: inconsistent property count");
}
float rotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation,
- mTransform[ROTATE_INDEX]);
+ mTransform[ROTATION_INDEX]);
float pivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX,
mTransform[PIVOT_X_INDEX]);
float pivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY,
@@ -1288,6 +1431,27 @@
String mPathName;
@Config int mChangingConfigurations;
+ private static final Property<VPath, PathParser.PathData> PATH_DATA =
+ new Property<VPath, PathParser.PathData>(PathParser.PathData.class, "pathData") {
+ @Override
+ public void set(VPath object, PathParser.PathData data) {
+ object.setPathData(data);
+ }
+
+ @Override
+ public PathParser.PathData get(VPath object) {
+ return object.getPathData();
+ }
+ };
+
+ Property getProperty(String propertyName) {
+ if (PATH_DATA.getName().equals(propertyName)) {
+ return PATH_DATA;
+ }
+ // property not found
+ return null;
+ }
+
public VPath() {
// Empty constructor.
}
@@ -1410,7 +1574,7 @@
private static final int NATIVE_ALLOCATION_SIZE = 264;
// Property map for animatable attributes.
- private final static HashMap<String, Integer> sPropertyMap
+ private final static HashMap<String, Integer> sPropertyIndexMap
= new HashMap<String, Integer> () {
{
put("strokeWidth", STROKE_WIDTH_INDEX);
@@ -1424,6 +1588,125 @@
}
};
+ // Below are the Properties that wrap the setters to avoid reflection overhead in animations
+ private static final Property<VFullPath, Float> STROKE_WIDTH =
+ new FloatProperty<VFullPath> ("strokeWidth") {
+ @Override
+ public void setValue(VFullPath object, float value) {
+ object.setStrokeWidth(value);
+ }
+
+ @Override
+ public Float get(VFullPath object) {
+ return object.getStrokeWidth();
+ }
+ };
+
+ private static final Property<VFullPath, Integer> STROKE_COLOR =
+ new IntProperty<VFullPath> ("strokeColor") {
+ @Override
+ public void setValue(VFullPath object, int value) {
+ object.setStrokeColor(value);
+ }
+
+ @Override
+ public Integer get(VFullPath object) {
+ return object.getStrokeColor();
+ }
+ };
+
+ private static final Property<VFullPath, Float> STROKE_ALPHA =
+ new FloatProperty<VFullPath> ("strokeAlpha") {
+ @Override
+ public void setValue(VFullPath object, float value) {
+ object.setStrokeAlpha(value);
+ }
+
+ @Override
+ public Float get(VFullPath object) {
+ return object.getStrokeAlpha();
+ }
+ };
+
+ private static final Property<VFullPath, Integer> FILL_COLOR =
+ new IntProperty<VFullPath>("fillColor") {
+ @Override
+ public void setValue(VFullPath object, int value) {
+ object.setFillColor(value);
+ }
+
+ @Override
+ public Integer get(VFullPath object) {
+ return object.getFillColor();
+ }
+ };
+
+ private static final Property<VFullPath, Float> FILL_ALPHA =
+ new FloatProperty<VFullPath> ("fillAlpha") {
+ @Override
+ public void setValue(VFullPath object, float value) {
+ object.setFillAlpha(value);
+ }
+
+ @Override
+ public Float get(VFullPath object) {
+ return object.getFillAlpha();
+ }
+ };
+
+ private static final Property<VFullPath, Float> TRIM_PATH_START =
+ new FloatProperty<VFullPath> ("trimPathStart") {
+ @Override
+ public void setValue(VFullPath object, float value) {
+ object.setTrimPathStart(value);
+ }
+
+ @Override
+ public Float get(VFullPath object) {
+ return object.getTrimPathStart();
+ }
+ };
+
+ private static final Property<VFullPath, Float> TRIM_PATH_END =
+ new FloatProperty<VFullPath> ("trimPathEnd") {
+ @Override
+ public void setValue(VFullPath object, float value) {
+ object.setTrimPathEnd(value);
+ }
+
+ @Override
+ public Float get(VFullPath object) {
+ return object.getTrimPathEnd();
+ }
+ };
+
+ private static final Property<VFullPath, Float> TRIM_PATH_OFFSET =
+ new FloatProperty<VFullPath> ("trimPathOffset") {
+ @Override
+ public void setValue(VFullPath object, float value) {
+ object.setTrimPathOffset(value);
+ }
+
+ @Override
+ public Float get(VFullPath object) {
+ return object.getTrimPathOffset();
+ }
+ };
+
+ private final static HashMap<String, Property> sPropertyMap
+ = new HashMap<String, Property> () {
+ {
+ put("strokeWidth", STROKE_WIDTH);
+ put("strokeColor", STROKE_COLOR);
+ put("strokeAlpha", STROKE_ALPHA);
+ put("fillColor", FILL_COLOR);
+ put("fillAlpha", FILL_ALPHA);
+ put("trimPathStart", TRIM_PATH_START);
+ put("trimPathEnd", TRIM_PATH_END);
+ put("trimPathOffset", TRIM_PATH_OFFSET);
+ }
+ };
+
// Temp array to store property data obtained from native getter.
private byte[] mPropertyData;
/////////////////////////////////////////////////////
@@ -1446,11 +1729,24 @@
mFillColors = copy.mFillColors;
}
+ Property getProperty(String propertyName) {
+ Property p = super.getProperty(propertyName);
+ if (p != null) {
+ return p;
+ }
+ if (sPropertyMap.containsKey(propertyName)) {
+ return sPropertyMap.get(propertyName);
+ } else {
+ // property not found
+ return null;
+ }
+ }
+
int getPropertyIndex(String propertyName) {
- if (!sPropertyMap.containsKey(propertyName)) {
+ if (!sPropertyIndexMap.containsKey(propertyName)) {
return -1;
} else {
- return sPropertyMap.get(propertyName);
+ return sPropertyIndexMap.get(propertyName);
}
}
@@ -1784,6 +2080,7 @@
abstract boolean onStateChange(int[] state);
abstract boolean isStateful();
abstract int getNativeSize();
+ abstract Property getProperty(String propertyName);
}
private static native long nCreateTree(long rootGroupPtr);
diff --git a/libs/hwui/AnimationContext.h b/libs/hwui/AnimationContext.h
index 909ed36..801fd87 100644
--- a/libs/hwui/AnimationContext.h
+++ b/libs/hwui/AnimationContext.h
@@ -100,6 +100,8 @@
ANDROID_API virtual void destroy();
+ ANDROID_API virtual void detachAnimators() {}
+
private:
friend class AnimationHandle;
void addAnimationHandle(AnimationHandle* handle);
diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp
index 4d65782..dc18018 100644
--- a/libs/hwui/Animator.cpp
+++ b/libs/hwui/Animator.cpp
@@ -274,6 +274,10 @@
return playTime >= mDuration;
}
+nsecs_t BaseRenderNodeAnimator::getRemainingPlayTime() {
+ return mPlayState == PlayState::Reversing ? mPlayTime : mDuration - mPlayTime;
+}
+
void BaseRenderNodeAnimator::forceEndNow(AnimationContext& context) {
if (mPlayState < PlayState::Finished) {
mPlayState = PlayState::Finished;
diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h
index fdae0f3..9476750 100644
--- a/libs/hwui/Animator.h
+++ b/libs/hwui/Animator.h
@@ -62,19 +62,23 @@
}
bool mayRunAsync() { return mMayRunAsync; }
ANDROID_API void start();
- ANDROID_API void reset();
+ ANDROID_API virtual void reset();
ANDROID_API void reverse();
// Terminates the animation at its current progress.
ANDROID_API void cancel();
// Terminates the animation and skip to the end of the animation.
- ANDROID_API void end();
+ ANDROID_API virtual void end();
void attach(RenderNode* target);
virtual void onAttached() {}
void detach() { mTarget = nullptr; }
- void pushStaging(AnimationContext& context);
- bool animate(AnimationContext& context);
+ ANDROID_API void pushStaging(AnimationContext& context);
+ ANDROID_API bool animate(AnimationContext& context);
+
+ // Returns the remaining time in ms for the animation. Note this should only be called during
+ // an animation on RenderThread.
+ ANDROID_API nsecs_t getRemainingPlayTime();
bool isRunning() { return mPlayState == PlayState::Running
|| mPlayState == PlayState::Reversing; }
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index b572bda..28be05c 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -45,7 +45,7 @@
, regions(stdAllocator)
, referenceHolders(stdAllocator)
, functors(stdAllocator)
- , pushStagingFunctors(stdAllocator)
+ , vectorDrawables(stdAllocator)
, hasDrawOps(false) {
}
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index 5b3227b..ccf71c6 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -69,6 +69,11 @@
typedef DrawRenderNodeOp NodeOpType;
#endif
+namespace VectorDrawable {
+class Tree;
+};
+typedef uirenderer::VectorDrawable::Tree VectorDrawableRoot;
+
/**
* Holds data used in the playback a tree of DisplayLists.
*/
@@ -110,16 +115,6 @@
LinearAllocator mReplayAllocator;
};
-/**
- * Functor that can be used for objects with data in both UI thread and RT to keep the data
- * in sync. This functor, when added to DisplayList, will be call during DisplayList sync.
- */
-struct PushStagingFunctor {
- PushStagingFunctor() {}
- virtual ~PushStagingFunctor() {}
- virtual void operator ()() {}
-};
-
struct FunctorContainer {
Functor* functor;
GlFunctorLifecycleListener* listener;
@@ -161,7 +156,7 @@
const LsaVector<const SkBitmap*>& getBitmapResources() const { return bitmapResources; }
const LsaVector<FunctorContainer>& getFunctors() const { return functors; }
- const LsaVector<PushStagingFunctor*>& getPushStagingFunctors() { return pushStagingFunctors; }
+ const LsaVector<VectorDrawableRoot*>& getVectorDrawables() { return vectorDrawables; }
size_t addChild(NodeOpType* childOp);
@@ -203,10 +198,10 @@
// List of functors
LsaVector<FunctorContainer> functors;
- // List of functors that need to be notified of pushStaging. Note that this list gets nothing
+ // List of VectorDrawables that need to be notified of pushStaging. Note that this list gets nothing
// but a callback during sync DisplayList, unlike the list of functors defined above, which
// gets special treatment exclusive for webview.
- LsaVector<PushStagingFunctor*> pushStagingFunctors;
+ LsaVector<VectorDrawableRoot*> vectorDrawables;
bool hasDrawOps; // only used if !HWUI_NEW_OPS
diff --git a/libs/hwui/DisplayListCanvas.cpp b/libs/hwui/DisplayListCanvas.cpp
index ca968ce..bec66295 100644
--- a/libs/hwui/DisplayListCanvas.cpp
+++ b/libs/hwui/DisplayListCanvas.cpp
@@ -417,7 +417,7 @@
void DisplayListCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
mDisplayList->ref(tree);
- mDisplayList->pushStagingFunctors.push_back(tree->getFunctor());
+ mDisplayList->vectorDrawables.push_back(tree);
addDrawOp(new (alloc()) DrawVectorDrawableOp(tree, tree->stagingProperties()->getBounds()));
}
diff --git a/libs/hwui/PropertyValuesAnimatorSet.cpp b/libs/hwui/PropertyValuesAnimatorSet.cpp
index b29f91f..e416e0c 100644
--- a/libs/hwui/PropertyValuesAnimatorSet.cpp
+++ b/libs/hwui/PropertyValuesAnimatorSet.cpp
@@ -30,6 +30,11 @@
interpolator, startDelay, duration, repeatCount);
mAnimators.emplace_back(animator);
setListener(new PropertyAnimatorSetListener(this));
+
+ // Check whether any child animator is infinite after adding it them to the set.
+ if (repeatCount == -1) {
+ mIsInfinite = true;
+ }
}
PropertyValuesAnimatorSet::PropertyValuesAnimatorSet()
@@ -78,15 +83,27 @@
void PropertyValuesAnimatorSet::start(AnimationListener* listener) {
init();
mOneShotListener = listener;
+ mRequestId++;
BaseRenderNodeAnimator::start();
}
void PropertyValuesAnimatorSet::reverse(AnimationListener* listener) {
init();
mOneShotListener = listener;
+ mRequestId++;
BaseRenderNodeAnimator::reverse();
}
+void PropertyValuesAnimatorSet::reset() {
+ mRequestId++;
+ BaseRenderNodeAnimator::reset();
+}
+
+void PropertyValuesAnimatorSet::end() {
+ mRequestId++;
+ BaseRenderNodeAnimator::end();
+}
+
void PropertyValuesAnimatorSet::init() {
if (mInitialized) {
return;
diff --git a/libs/hwui/PropertyValuesAnimatorSet.h b/libs/hwui/PropertyValuesAnimatorSet.h
index c7ae7c0..49021bc 100644
--- a/libs/hwui/PropertyValuesAnimatorSet.h
+++ b/libs/hwui/PropertyValuesAnimatorSet.h
@@ -43,6 +43,7 @@
float mLatestFraction = 0.0f;
};
+// TODO: This class should really be named VectorDrawableAnimator
class ANDROID_API PropertyValuesAnimatorSet : public BaseRenderNodeAnimator {
public:
friend class PropertyAnimatorSetListener;
@@ -50,11 +51,19 @@
void start(AnimationListener* listener);
void reverse(AnimationListener* listener);
+ virtual void reset() override;
+ virtual void end() override;
void addPropertyAnimator(PropertyValuesHolder* propertyValuesHolder,
Interpolator* interpolators, int64_t startDelays,
nsecs_t durations, int repeatCount);
virtual uint32_t dirtyMask();
+ bool isInfinite() { return mIsInfinite; }
+ void setVectorDrawable(VectorDrawableRoot* vd) { mVectorDrawable = vd; }
+ VectorDrawableRoot* getVectorDrawable() const { return mVectorDrawable; }
+ AnimationListener* getOneShotListener() { return mOneShotListener.get(); }
+ void clearOneShotListener() { mOneShotListener = nullptr; }
+ uint32_t getRequestId() const { return mRequestId; }
protected:
virtual float getValue(RenderNode* target) const override;
@@ -69,6 +78,11 @@
std::vector< std::unique_ptr<PropertyAnimator> > mAnimators;
float mLastFraction = 0.0f;
bool mInitialized = false;
+ VectorDrawableRoot* mVectorDrawable = nullptr;
+ bool mIsInfinite = false;
+ // This request id gets incremented (on UI thread only) when a new request to modfiy the
+ // lifecycle of an animation happens, namely when start/end/reset/reverse is called.
+ uint32_t mRequestId = 0;
};
class PropertyAnimatorSetListener : public AnimationListener {
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index b49f9b5..b35c926 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -440,8 +440,8 @@
}
void RecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
- mDisplayList->pushStagingFunctors.push_back(tree->getFunctor());
mDisplayList->ref(tree);
+ mDisplayList->vectorDrawables.push_back(tree);
addOp(alloc().create_trivial<VectorDrawableOp>(
tree,
Rect(tree->stagingProperties()->getBounds()),
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 6e848fd..0f6c43e 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -419,6 +419,14 @@
prepareSubTree(info, childFunctorsNeedLayer, mDisplayList);
pushLayerUpdate(info);
+ for (auto& vectorDrawable : mDisplayList->getVectorDrawables()) {
+ // If any vector drawable in the display list needs update, damage the node.
+ if (vectorDrawable->isDirty()) {
+ damageSelf(info);
+ }
+ vectorDrawable->setPropertyChangeWillBeConsumed(true);
+ }
+
info.damageAccumulator->popTransform();
}
@@ -477,8 +485,8 @@
for (auto& iter : mDisplayList->getFunctors()) {
(*iter.functor)(DrawGlInfo::kModeSync, nullptr);
}
- for (size_t i = 0; i < mDisplayList->getPushStagingFunctors().size(); i++) {
- (*mDisplayList->getPushStagingFunctors()[i])();
+ for (auto& vectorDrawable : mDisplayList->getVectorDrawables()) {
+ vectorDrawable->syncProperties();
}
}
}
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index a5d1d4b..e67dfdd 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -673,21 +673,16 @@
void onPropertyChanged(TreeProperties* prop);
TreeProperties* mutateStagingProperties() { return &mStagingProperties; }
const TreeProperties* stagingProperties() const { return &mStagingProperties; }
- PushStagingFunctor* getFunctor() { return &mFunctor;}
// This should only be called from animations on RT
TreeProperties* mutateProperties() { return &mProperties; }
+ // This should always be called from RT.
+ bool isDirty() const { return mCache.dirty; }
+ bool getPropertyChangeWillBeConsumed() const { return mWillBeConsumed; }
+ void setPropertyChangeWillBeConsumed(bool willBeConsumed) { mWillBeConsumed = willBeConsumed; }
+
private:
- class VectorDrawableFunctor : public PushStagingFunctor {
- public:
- VectorDrawableFunctor(Tree* tree) : mTree(tree) {}
- virtual void operator ()() {
- mTree->syncProperties();
- }
- private:
- Tree* mTree;
- };
SkPaint* updatePaint(SkPaint* outPaint, TreeProperties* prop);
bool allocateBitmapIfNeeded(SkBitmap* outCache, int width, int height);
@@ -704,8 +699,6 @@
TreeProperties mProperties = TreeProperties(this);
TreeProperties mStagingProperties = TreeProperties(this);
- VectorDrawableFunctor mFunctor = VectorDrawableFunctor(this);
-
SkPaint mPaint;
struct Cache {
SkBitmap bitmap;
@@ -717,6 +710,8 @@
PropertyChangedListener mPropertyChangedListener
= PropertyChangedListener(&mCache.dirty, &mStagingCache.dirty);
+
+ mutable bool mWillBeConsumed = false;
};
} // namespace VectorDrawable
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index e6399d4..597c5c5 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -278,6 +278,7 @@
void CanvasContext::stopDrawing() {
mRenderThread.removeFrameCallback(this);
+ mAnimationContext->detachAnimators();
}
void CanvasContext::notifyFramePending() {
diff --git a/packages/PrintRecommendationService/res/values/strings.xml b/packages/PrintRecommendationService/res/values/strings.xml
index 348fcac..b6c45b7 100644
--- a/packages/PrintRecommendationService/res/values/strings.xml
+++ b/packages/PrintRecommendationService/res/values/strings.xml
@@ -26,6 +26,6 @@
<string name="plugin_vendor_samsung">Samsung</string>
<string name="plugin_vendor_epson">Epson</string>
<string name="plugin_vendor_konica_minolta">Konica Minolta</string>
- <string name="plugin_vendor_fuji">Fuji</string>
+ <string name="plugin_vendor_fuji_xerox">Fuji Xerox</string>
<string name="plugin_vendor_morpia">Mopria</string>
</resources>
diff --git a/packages/PrintRecommendationService/res/xml/vendorconfigs.xml b/packages/PrintRecommendationService/res/xml/vendorconfigs.xml
index 52889ce..703cf6f 100644
--- a/packages/PrintRecommendationService/res/xml/vendorconfigs.xml
+++ b/packages/PrintRecommendationService/res/xml/vendorconfigs.xml
@@ -60,7 +60,7 @@
</vendor>
<vendor>
- <name>@string/plugin_vendor_fuji</name>
+ <name>@string/plugin_vendor_fuji_xerox</name>
<package>jp.co.fujixerox.prt.PrintUtil.PCL</package>
<mdns-names>
<mdns-name>FUJI XEROX</mdns-name>
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/xerox/MDnsUtils.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/xerox/MDnsUtils.java
index 7a2d0d89..b0da08bf 100755
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/xerox/MDnsUtils.java
+++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/xerox/MDnsUtils.java
@@ -39,8 +39,10 @@
String usbMfg = getString(attributes.get(ATTRIBUTE__USB_MFG));
String usbMdl = getString(attributes.get(ATTRIBUTE__USB_MDL));
String mfg = getString(attributes.get(ATTRIBUTE__MFG));
- return containsVendor(product, vendorValues) || containsVendor(ty, vendorValues) || containsVendor(usbMfg, vendorValues) || containsVendor(mfg, vendorValues) && !(containsString(ty, EXCLUDE_FUJI) || containsString(product, EXCLUDE_FUJI) || containsString(usbMdl, EXCLUDE_FUJI));
-
+ return (containsVendor(product, vendorValues) || containsVendor(ty, vendorValues) ||
+ containsVendor(usbMfg, vendorValues) || containsVendor(mfg, vendorValues)) &&
+ !(containsString(ty, EXCLUDE_FUJI) || containsString(product, EXCLUDE_FUJI) ||
+ containsString(usbMdl, EXCLUDE_FUJI));
}
public static String getVendor(NsdServiceInfo networkDevice) {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index be3df54..c318275 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -614,6 +614,9 @@
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
+
+ mMediaSizeComparator.onConfigurationChanged(newConfig);
+
if (mPrintPreviewController != null) {
mPrintPreviewController.onOrientationChanged();
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/util/MediaSizeUtils.java b/packages/PrintSpooler/src/com/android/printspooler/util/MediaSizeUtils.java
index 912ee1d..7289301 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/util/MediaSizeUtils.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/util/MediaSizeUtils.java
@@ -16,13 +16,16 @@
package com.android.printspooler.util;
+import android.annotation.NonNull;
import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
import android.print.PrintAttributes.MediaSize;
-import android.util.ArrayMap;
import com.android.printspooler.R;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.Map;
/**
@@ -30,7 +33,10 @@
*/
public final class MediaSizeUtils {
- private static Map<MediaSize, String> sMediaSizeToStandardMap;
+ private static Map<MediaSize, Integer> sMediaSizeToStandardMap;
+
+ /** The media size standard for all media sizes no standard is defined for */
+ private static int sMediaSizeStandardIso;
private MediaSizeUtils() {
/* do nothing - hide constructor */
@@ -47,22 +53,32 @@
return MediaSize.getStandardMediaSizeById(mediaSizeId);
}
- private static String getStandardForMediaSize(Context context, MediaSize mediaSize) {
+ /**
+ * Get the standard the {@link MediaSize} belongs to.
+ *
+ * @param context The context of the caller
+ * @param mediaSize The {@link MediaSize} to be resolved
+ *
+ * @return The standard the {@link MediaSize} belongs to
+ */
+ private static int getStandardForMediaSize(Context context, MediaSize mediaSize) {
if (sMediaSizeToStandardMap == null) {
- sMediaSizeToStandardMap = new ArrayMap<MediaSize, String>();
+ sMediaSizeStandardIso = Integer.parseInt(context.getString(
+ R.string.mediasize_standard_iso));
+
+ sMediaSizeToStandardMap = new HashMap<>();
String[] mediaSizeToStandardMapValues = context.getResources()
.getStringArray(R.array.mediasize_to_standard_map);
final int mediaSizeToStandardCount = mediaSizeToStandardMapValues.length;
for (int i = 0; i < mediaSizeToStandardCount; i += 2) {
String mediaSizeId = mediaSizeToStandardMapValues[i];
MediaSize key = MediaSize.getStandardMediaSizeById(mediaSizeId);
- String value = mediaSizeToStandardMapValues[i + 1];
+ int value = Integer.parseInt(mediaSizeToStandardMapValues[i + 1]);
sMediaSizeToStandardMap.put(key, value);
}
}
- String standard = sMediaSizeToStandardMap.get(mediaSize);
- return (standard != null) ? standard : context.getString(
- R.string.mediasize_standard_iso);
+ Integer standard = sMediaSizeToStandardMap.get(mediaSize);
+ return (standard != null) ? standard : sMediaSizeStandardIso;
}
/**
@@ -73,32 +89,76 @@
public static final class MediaSizeComparator implements Comparator<MediaSize> {
private final Context mContext;
+ /** Current configuration */
+ private Configuration mCurrentConfig;
+
+ /** The standard to use for the current locale */
+ private int mCurrentStandard;
+
+ /** Mapping from media size to label */
+ private final @NonNull Map<MediaSize, String> mMediaSizeToLabel;
+
public MediaSizeComparator(Context context) {
mContext = context;
+ mMediaSizeToLabel = new HashMap<>();
+ mCurrentStandard = Integer.parseInt(mContext.getString(R.string.mediasize_standard));
+ }
+
+ /**
+ * Handle a configuration change by reloading all resources.
+ *
+ * @param newConfig The new configuration that will be applied.
+ */
+ public void onConfigurationChanged(@NonNull Configuration newConfig) {
+ if (mCurrentConfig == null ||
+ (newConfig.diff(mCurrentConfig) & ActivityInfo.CONFIG_LOCALE) != 0) {
+ mCurrentStandard = Integer
+ .parseInt(mContext.getString(R.string.mediasize_standard));
+ mMediaSizeToLabel.clear();
+
+ mCurrentConfig = newConfig;
+ }
+ }
+
+ /**
+ * Get the label for a {@link MediaSize}.
+ *
+ * @param context The context the label should be loaded for
+ * @param mediaSize The {@link MediaSize} to resolve
+ *
+ * @return The label for the media size
+ */
+ public @NonNull String getLabel(@NonNull Context context, @NonNull MediaSize mediaSize) {
+ String label = mMediaSizeToLabel.get(mediaSize);
+
+ if (label == null) {
+ label = mediaSize.getLabel(context.getPackageManager());
+ mMediaSizeToLabel.put(mediaSize, label);
+ }
+
+ return label;
}
@Override
public int compare(MediaSize lhs, MediaSize rhs) {
- String currentStandard = mContext.getString(R.string.mediasize_standard);
- String lhsStandard = getStandardForMediaSize(mContext, lhs);
- String rhsStandard = getStandardForMediaSize(mContext, rhs);
+ int lhsStandard = getStandardForMediaSize(mContext, lhs);
+ int rhsStandard = getStandardForMediaSize(mContext, rhs);
// The current standard always wins.
- if (lhsStandard.equals(currentStandard)) {
- if (!rhsStandard.equals(currentStandard)) {
+ if (lhsStandard == mCurrentStandard) {
+ if (rhsStandard != mCurrentStandard) {
return -1;
}
- } else if (rhsStandard.equals(currentStandard)) {
+ } else if (rhsStandard == mCurrentStandard) {
return 1;
}
- if (!lhsStandard.equals(rhsStandard)) {
+ if (lhsStandard != rhsStandard) {
// Different standards - use the standard ordering.
- return lhsStandard.compareTo(rhsStandard);
+ return Integer.valueOf(lhsStandard).compareTo(rhsStandard);
} else {
// Same standard - sort alphabetically by label.
- return lhs.getLabel(mContext.getPackageManager()).
- compareTo(rhs.getLabel(mContext.getPackageManager()));
+ return getLabel(mContext, lhs).compareTo(getLabel(mContext, rhs));
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
index dba7130..bfa43fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
@@ -42,6 +42,7 @@
private float mViewAlpha = 1.0f;
private ValueAnimator mAlphaAnimator;
private Rect mExcludedRect = new Rect();
+ private int mLeftInset = 0;
private boolean mHasExcludedArea;
private ValueAnimator.AnimatorUpdateListener mAlphaUpdateListener
= new ValueAnimator.AnimatorUpdateListener() {
@@ -87,12 +88,12 @@
if (mExcludedRect.top > 0) {
canvas.drawRect(0, 0, getWidth(), mExcludedRect.top, mPaint);
}
- if (mExcludedRect.left > 0) {
- canvas.drawRect(0, mExcludedRect.top, mExcludedRect.left, mExcludedRect.bottom,
- mPaint);
+ if (mExcludedRect.left + mLeftInset > 0) {
+ canvas.drawRect(0, mExcludedRect.top, mExcludedRect.left + mLeftInset,
+ mExcludedRect.bottom, mPaint);
}
- if (mExcludedRect.right < getWidth()) {
- canvas.drawRect(mExcludedRect.right,
+ if (mExcludedRect.right + mLeftInset < getWidth()) {
+ canvas.drawRect(mExcludedRect.right + mLeftInset,
mExcludedRect.top,
getWidth(),
mExcludedRect.bottom,
@@ -183,4 +184,14 @@
public void setChangeRunnable(Runnable changeRunnable) {
mChangeRunnable = changeRunnable;
}
+
+ public void setLeftInset(int leftInset) {
+ if (mLeftInset != leftInset) {
+ mLeftInset = leftInset;
+
+ if (mHasExcludedArea) {
+ invalidate();
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 9c4480e..135c294 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -524,6 +524,10 @@
mScrimBehind.setExcludedArea(area);
}
+ public void setLeftInset(int inset) {
+ mScrimBehind.setLeftInset(inset);
+ }
+
public int getScrimBehindColor() {
return mScrimBehind.getScrimColorWithAlpha();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index ebfa018..7b22b88 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -70,6 +70,7 @@
private View mBrightnessMirror;
private int mRightInset = 0;
+ private int mLeftInset = 0;
private PhoneStatusBar mService;
private final Paint mTransparentSrcPaint = new Paint();
@@ -93,25 +94,26 @@
@Override
protected boolean fitSystemWindows(Rect insets) {
if (getFitsSystemWindows()) {
- boolean paddingChanged = insets.left != getPaddingLeft()
- || insets.top != getPaddingTop()
+ boolean paddingChanged = insets.top != getPaddingTop()
|| insets.bottom != getPaddingBottom();
// Super-special right inset handling, because scrims and backdrop need to ignore it.
- if (insets.right != mRightInset) {
+ if (insets.right != mRightInset || insets.left != mLeftInset) {
mRightInset = insets.right;
+ mLeftInset = insets.left;
applyMargins();
}
- // Drop top inset, apply left inset and pass through bottom inset.
+ // Drop top inset, and pass through bottom inset.
if (paddingChanged) {
- setPadding(insets.left, 0, 0, 0);
+ setPadding(0, 0, 0, 0);
}
insets.left = 0;
insets.top = 0;
insets.right = 0;
} else {
- if (mRightInset != 0) {
+ if (mRightInset != 0 || mLeftInset != 0) {
mRightInset = 0;
+ mLeftInset = 0;
applyMargins();
}
boolean changed = getPaddingLeft() != 0
@@ -127,13 +129,16 @@
}
private void applyMargins() {
+ mService.mScrimController.setLeftInset(mLeftInset);
final int N = getChildCount();
for (int i = 0; i < N; i++) {
View child = getChildAt(i);
if (child.getLayoutParams() instanceof LayoutParams) {
LayoutParams lp = (LayoutParams) child.getLayoutParams();
- if (!lp.ignoreRightInset && lp.rightMargin != mRightInset) {
+ if (!lp.ignoreRightInset
+ && (lp.rightMargin != mRightInset || lp.leftMargin != mLeftInset)) {
lp.rightMargin = mRightInset;
+ lp.leftMargin = mLeftInset;
child.requestLayout();
}
}
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index d58f864..71964d1 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -222,7 +222,7 @@
} catch (RemoteException e) {
Slog.e(TAG,"Unable to call onBrEdrDown", e);
} finally {
- mBluetoothLock.readLock().lock();
+ mBluetoothLock.readLock().unlock();
}
} else if (st == BluetoothAdapter.STATE_ON){
// disable without persisting the setting
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index b89cae7..793f411 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -167,8 +167,9 @@
private Intent mNewTaskIntent;
private ActivityStack mSourceStack;
private ActivityStack mTargetStack;
- // TODO: Is the mMoveHome flag really needed?
- private boolean mMovedHome;
+ // Indicates that we moved other task and are going to put something on top soon, so
+ // we don't want to show it redundantly or accidentally change what's shown below.
+ private boolean mMovedOtherTask;
private boolean mMovedToFront;
private boolean mNoAnimation;
private boolean mKeepCurTransition;
@@ -206,7 +207,7 @@
mSourceStack = null;
mTargetStack = null;
- mMovedHome = false;
+ mMovedOtherTask = false;
mMovedToFront = false;
mNoAnimation = false;
mKeepCurTransition = false;
@@ -1039,7 +1040,6 @@
resumeTargetStackIfNeeded();
return START_RETURN_INTENT_TO_CALLER;
}
-
setTaskFromIntentActivity(mReusedActivity);
if (!mAddingToTask && mReuseTask == null) {
@@ -1108,7 +1108,7 @@
Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
return START_RETURN_LOCK_TASK_MODE_VIOLATION;
}
- if (!mMovedHome) {
+ if (!mMovedOtherTask) {
updateTaskReturnToType(mStartActivity.task, mLaunchFlags, topStack);
}
} else if (mSourceRecord != null) {
@@ -1472,7 +1472,7 @@
if (mLaunchTaskBehind && mSourceRecord != null) {
intentActivity.setTaskToAffiliateWith(mSourceRecord.task);
}
- mMovedHome = true;
+ mMovedOtherTask = true;
// If the launch flags carry both NEW_TASK and CLEAR_TASK, the task's activities
// will be cleared soon by ActivityStarter in setTaskFromIntentActivity().
@@ -1550,6 +1550,10 @@
mReuseTask = intentActivity.task;
mReuseTask.performClearTaskLocked();
mReuseTask.setIntent(mStartActivity);
+ // When we clear the task - focus will be adjusted, which will bring another task
+ // to top before we launch the activity we need. This will temporary swap their
+ // mTaskToReturnTo values and we don't want to overwrite them accidentally.
+ mMovedOtherTask = true;
} else if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
|| mLaunchSingleInstance || mLaunchSingleTask) {
ActivityRecord top = intentActivity.task.performClearTaskLocked(mStartActivity,
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index e0cfe4e..fae743c 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -262,6 +262,10 @@
private static final String SYSUI_SCREENSHOT_ERROR_RECEIVER =
"com.android.systemui.screenshot.ScreenshotServiceErrorReceiver";
+ private static final int NAV_BAR_BOTTOM = 0;
+ private static final int NAV_BAR_RIGHT = 1;
+ private static final int NAV_BAR_LEFT = 2;
+
/**
* Keyguard stuff
*/
@@ -354,9 +358,8 @@
int mStatusBarHeight;
WindowState mNavigationBar = null;
boolean mHasNavigationBar = false;
- boolean mCanHideNavigationBar = false;
boolean mNavigationBarCanMove = false; // can the navigation bar ever move to the side?
- boolean mNavigationBarOnBottom = true; // is the navigation bar on the bottom *right now*?
+ int mNavigationBarPosition = NAV_BAR_BOTTOM;
int[] mNavigationBarHeightForRotationDefault = new int[4];
int[] mNavigationBarWidthForRotationDefault = new int[4];
int[] mNavigationBarHeightForRotationInCarMode = new int[4];
@@ -1683,13 +1686,19 @@
}
@Override
public void onSwipeFromBottom() {
- if (mNavigationBar != null && mNavigationBarOnBottom) {
+ if (mNavigationBar != null && mNavigationBarPosition == NAV_BAR_BOTTOM) {
requestTransientBars(mNavigationBar);
}
}
@Override
public void onSwipeFromRight() {
- if (mNavigationBar != null && !mNavigationBarOnBottom) {
+ if (mNavigationBar != null && mNavigationBarPosition == NAV_BAR_RIGHT) {
+ requestTransientBars(mNavigationBar);
+ }
+ }
+ @Override
+ public void onSwipeFromLeft() {
+ if (mNavigationBar != null && mNavigationBarPosition == NAV_BAR_LEFT) {
requestTransientBars(mNavigationBar);
}
}
@@ -2778,8 +2787,8 @@
if (win.getAttrs().windowAnimations != 0) {
return 0;
}
- // This can be on either the bottom or the right.
- if (mNavigationBarOnBottom) {
+ // This can be on either the bottom or the right or the left.
+ if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
if (transit == TRANSIT_EXIT
|| transit == TRANSIT_HIDE) {
return R.anim.dock_bottom_exit;
@@ -2787,7 +2796,7 @@
|| transit == TRANSIT_SHOW) {
return R.anim.dock_bottom_enter;
}
- } else {
+ } else if (mNavigationBarPosition == NAV_BAR_RIGHT) {
if (transit == TRANSIT_EXIT
|| transit == TRANSIT_HIDE) {
return R.anim.dock_right_exit;
@@ -2795,6 +2804,14 @@
|| transit == TRANSIT_SHOW) {
return R.anim.dock_right_enter;
}
+ } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
+ if (transit == TRANSIT_EXIT
+ || transit == TRANSIT_HIDE) {
+ return R.anim.dock_left_exit;
+ } else if (transit == TRANSIT_ENTER
+ || transit == TRANSIT_SHOW) {
+ return R.anim.dock_left_enter;
+ }
}
} else if (win.getAttrs().type == TYPE_DOCK_DIVIDER) {
return selectDockedDividerAnimationLw(win, transit);
@@ -2823,10 +2840,12 @@
// If the divider is behind the navigation bar, don't animate.
final Rect frame = win.getFrameLw();
final boolean behindNavBar = mNavigationBar != null
- && ((mNavigationBarOnBottom
+ && ((mNavigationBarPosition == NAV_BAR_BOTTOM
&& frame.top + insets >= mNavigationBar.getFrameLw().top)
- || (!mNavigationBarOnBottom
- && frame.left + insets >= mNavigationBar.getFrameLw().left));
+ || (mNavigationBarPosition == NAV_BAR_RIGHT
+ && frame.left + insets >= mNavigationBar.getFrameLw().left)
+ || (mNavigationBarPosition == NAV_BAR_LEFT
+ && frame.right - insets <= mNavigationBar.getFrameLw().right));
final boolean landscape = frame.height() > frame.width();
final boolean offscreenLandscape = landscape && (frame.right - insets <= 0
|| frame.left + insets >= win.getDisplayFrameLw().right);
@@ -4019,7 +4038,7 @@
navVisible |= !canHideNavigationBar();
boolean updateSysUiVisibility = layoutNavigationBar(displayWidth, displayHeight,
- displayRotation, uiMode, overscanRight, overscanBottom, dcf, navVisible, navTranslucent,
+ displayRotation, uiMode, overscanLeft, overscanRight, overscanBottom, dcf, navVisible, navTranslucent,
navAllowedHidden, statusBarExpandedNotKeyguard);
if (DEBUG_LAYOUT) Slog.i(TAG, String.format("mDock rect: (%d,%d - %d,%d)",
mDockLeft, mDockTop, mDockRight, mDockBottom));
@@ -4098,8 +4117,8 @@
}
private boolean layoutNavigationBar(int displayWidth, int displayHeight, int displayRotation,
- int uiMode, int overscanRight, int overscanBottom, Rect dcf, boolean navVisible,
- boolean navTranslucent, boolean navAllowedHidden,
+ int uiMode, int overscanLeft, int overscanRight, int overscanBottom, Rect dcf,
+ boolean navVisible, boolean navTranslucent, boolean navAllowedHidden,
boolean statusBarExpandedNotKeyguard) {
if (mNavigationBar != null) {
boolean transientNavBarShowing = mNavigationBarController.isTransientShowing();
@@ -4107,8 +4126,9 @@
// size. We need to do this directly, instead of relying on
// it to bubble up from the nav bar, because this needs to
// change atomically with screen rotations.
- mNavigationBarOnBottom = isNavigationBarOnBottom(displayWidth, displayHeight);
- if (mNavigationBarOnBottom) {
+ mNavigationBarPosition = navigationBarPosition(displayWidth, displayHeight,
+ displayRotation);
+ if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
// It's a system nav bar or a portrait screen; nav bar goes on bottom.
int top = displayHeight - overscanBottom
- getNavigationBarHeight(displayRotation, uiMode);
@@ -4134,7 +4154,7 @@
// we can tell the app that it is covered by it.
mSystemBottom = mTmpNavigationFrame.top;
}
- } else {
+ } else if (mNavigationBarPosition == NAV_BAR_RIGHT) {
// Landscape screen; nav bar goes to the right.
int left = displayWidth - overscanRight
- getNavigationBarWidth(displayRotation, uiMode);
@@ -4160,6 +4180,33 @@
// we can tell the app that it is covered by it.
mSystemRight = mTmpNavigationFrame.left;
}
+ } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
+ // Seascape screen; nav bar goes to the left.
+ int right = overscanLeft + getNavigationBarWidth(displayRotation, uiMode);
+ mTmpNavigationFrame.set(overscanLeft, 0, right, displayHeight);
+ mStableLeft = mStableFullscreenLeft = mTmpNavigationFrame.right;
+ if (transientNavBarShowing) {
+ mNavigationBarController.setBarShowingLw(true);
+ } else if (navVisible) {
+ mNavigationBarController.setBarShowingLw(true);
+ mDockLeft = mTmpNavigationFrame.right;
+ // TODO: not so sure about those:
+ mRestrictedScreenLeft = mRestrictedOverscanScreenLeft = mDockLeft;
+ mRestrictedScreenWidth = mDockRight - mRestrictedScreenLeft;
+ mRestrictedOverscanScreenWidth = mDockRight - mRestrictedOverscanScreenLeft;
+ } else {
+ // We currently want to hide the navigation UI - unless we expanded the status
+ // bar.
+ mNavigationBarController.setBarShowingLw(statusBarExpandedNotKeyguard);
+ }
+ if (navVisible && !navTranslucent && !navAllowedHidden
+ && !mNavigationBar.isAnimatingLw()
+ && !mNavigationBarController.wasRecentlyTranslucent()) {
+ // If the nav bar is currently requested to be visible,
+ // and not in the process of animating on or off, then
+ // we can tell the app that it is covered by it.
+ mSystemLeft = mTmpNavigationFrame.right;
+ }
}
// Make sure the content and current rectangles are updated to
// account for the restrictions from the navigation bar.
@@ -4180,8 +4227,15 @@
return false;
}
- private boolean isNavigationBarOnBottom(int displayWidth, int displayHeight) {
- return !mNavigationBarCanMove || displayWidth < displayHeight;
+ private int navigationBarPosition(int displayWidth, int displayHeight, int displayRotation) {
+ if (mNavigationBarCanMove && displayWidth > displayHeight) {
+ if (displayRotation == Surface.ROTATION_270) {
+ return NAV_BAR_LEFT;
+ } else {
+ return NAV_BAR_RIGHT;
+ }
+ }
+ return NAV_BAR_BOTTOM;
}
/** {@inheritDoc} */
@@ -4357,7 +4411,11 @@
if (mStatusBar != null && mFocusedWindow == mStatusBar && canReceiveInput(mStatusBar)) {
// The status bar forces the navigation bar while it's visible. Make sure the IME
// avoids the navigation bar in that case.
- pf.right = df.right = of.right = cf.right = vf.right = mStableRight;
+ if (mNavigationBarPosition == NAV_BAR_RIGHT) {
+ pf.right = df.right = of.right = cf.right = vf.right = mStableRight;
+ } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
+ pf.left = df.left = of.left = cf.left = vf.left = mStableLeft;
+ }
}
// IM dock windows always go to the bottom of the screen.
attrs.gravity = Gravity.BOTTOM;
@@ -6463,10 +6521,13 @@
// Only navigation bar
if (mNavigationBar != null) {
- if (isNavigationBarOnBottom(displayWidth, displayHeight)) {
+ int position = navigationBarPosition(displayWidth, displayHeight, displayRotation);
+ if (position == NAV_BAR_BOTTOM) {
outInsets.bottom = getNavigationBarHeight(displayRotation, mUiMode);
- } else {
+ } else if (position == NAV_BAR_RIGHT) {
outInsets.right = getNavigationBarWidth(displayRotation, mUiMode);
+ } else if (position == NAV_BAR_LEFT) {
+ outInsets.left = getNavigationBarWidth(displayRotation, mUiMode);
}
}
}
diff --git a/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java b/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
index 80e4341..598c58e 100644
--- a/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
+++ b/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
@@ -43,6 +43,7 @@
private static final int SWIPE_FROM_TOP = 1;
private static final int SWIPE_FROM_BOTTOM = 2;
private static final int SWIPE_FROM_RIGHT = 3;
+ private static final int SWIPE_FROM_LEFT = 4;
private final Context mContext;
private final int mSwipeStartThreshold;
@@ -127,6 +128,9 @@
} else if (swipe == SWIPE_FROM_RIGHT) {
if (DEBUG) Slog.d(TAG, "Firing onSwipeFromRight");
mCallbacks.onSwipeFromRight();
+ } else if (swipe == SWIPE_FROM_LEFT) {
+ if (DEBUG) Slog.d(TAG, "Firing onSwipeFromLeft");
+ mCallbacks.onSwipeFromLeft();
}
}
break;
@@ -229,6 +233,11 @@
&& elapsed < SWIPE_TIMEOUT_MS) {
return SWIPE_FROM_RIGHT;
}
+ if (fromX <= mSwipeStartThreshold
+ && x > fromX + mSwipeDistanceThreshold
+ && elapsed < SWIPE_TIMEOUT_MS) {
+ return SWIPE_FROM_LEFT;
+ }
return SWIPE_NONE;
}
@@ -265,6 +274,7 @@
void onSwipeFromTop();
void onSwipeFromBottom();
void onSwipeFromRight();
+ void onSwipeFromLeft();
void onFling(int durationMs);
void onDown();
void onUpOrCancel();
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index e46ed8d..881fc10 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1314,7 +1314,6 @@
}
private int resolveStackClip() {
-
// App animation overrides window animation stack clip mode.
if (mAppAnimator != null && mAppAnimator.animation != null) {
return mAppAnimator.getStackClip();
@@ -1420,6 +1419,9 @@
// aren't observing known issues here outside of PiP resizing. (Typically
// the other windows that use -1 are PopupWindows which aren't likely
// to be rendering while we resize).
+
+ boolean wasForceScaled = mForceScaleUntilResize;
+
if (!w.inPinnedWorkspace() || (!w.mRelayoutCalled || w.mInRelayout)) {
mSurfaceResized = mSurfaceController.setSizeInTransaction(
mTmpSize.width(), mTmpSize.height(), recoveringMemory);
@@ -1428,13 +1430,17 @@
}
mForceScaleUntilResize = mForceScaleUntilResize && !mSurfaceResized;
-
calculateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect);
+
+ float surfaceWidth = mSurfaceController.getWidth();
+ float surfaceHeight = mSurfaceController.getHeight();
+
if ((task != null && task.mStack.getForceScaleToCrop()) || mForceScaleUntilResize) {
int hInsets = w.getAttrs().surfaceInsets.left + w.getAttrs().surfaceInsets.right;
int vInsets = w.getAttrs().surfaceInsets.top + w.getAttrs().surfaceInsets.bottom;
- float surfaceWidth = mSurfaceController.getWidth();
- float surfaceHeight = mSurfaceController.getHeight();
+ if (!mForceScaleUntilResize) {
+ mSurfaceController.forceScaleableInTransaction(true);
+ }
// We want to calculate the scaling based on the content area, not based on
// the entire surface, so that we scale in sync with windows that don't have insets.
mExtraHScale = (mTmpClipRect.width() - hInsets) / (float)(surfaceWidth - hInsets);
@@ -1455,7 +1461,8 @@
posX += w.getAttrs().surfaceInsets.left * (1 - mExtraHScale);
posY += w.getAttrs().surfaceInsets.top * (1 - mExtraVScale);
- mSurfaceController.setPositionInTransaction(posX, posY, recoveringMemory);
+ mSurfaceController.setPositionInTransaction((float)Math.floor(posX),
+ (float)Math.floor(posY), recoveringMemory);
// Since we are scaled to fit in our previously desired crop, we can now
// expose the whole window in buffer space, and not risk extending
@@ -1467,7 +1474,7 @@
// We need to ensure for each surface, that we disable transformation matrix
// scaling in the same transaction which we resize the surface in.
// As we are in SCALING_MODE_SCALE_TO_WINDOW, SurfaceFlinger will
- // then take over the scaling until the new buffer arrives, and things
+ // then take over the scaling until the new buffer arrives, and things
// will be seamless.
mForceScaleUntilResize = true;
} else {
@@ -1475,6 +1482,22 @@
recoveringMemory);
}
+ // If we are ending the scaling mode. We switch to SCALING_MODE_FREEZE
+ // to prevent further updates until buffer latch. Normally position
+ // would continue to apply immediately. But we need a different position
+ // before and after resize (since we have scaled the shadows, as discussed
+ // above).
+ if (wasForceScaled && !mForceScaleUntilResize) {
+ mSurfaceController.setPositionAppliesWithResizeInTransaction(true);
+ mSurfaceController.forceScaleableInTransaction(false);
+ }
+ if (w.inPinnedWorkspace()) {
+ mTmpClipRect.set(0, 0, -1, -1);
+ task.mStack.getDimBounds(mTmpFinalClipRect);
+ mTmpFinalClipRect.inset(-w.mAttrs.surfaceInsets.left, -w.mAttrs.surfaceInsets.top,
+ -w.mAttrs.surfaceInsets.right, -w.mAttrs.surfaceInsets.bottom);
+ }
+
updateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect, recoveringMemory);
mSurfaceController.setMatrixInTransaction(mDsDx * w.mHScale * mExtraHScale,
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 9646a49..c30da14 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -176,7 +176,7 @@
if (SHOW_TRANSACTIONS) logSurface(
"CROP " + clipRect.toShortString(), null);
try {
- if (clipRect.width() > 0 && clipRect.height() > 0) {
+ if (clipRect.width() != 0 && clipRect.height() != 0) {
mSurfaceControl.setWindowCrop(clipRect);
mHiddenForCrop = false;
updateVisibility();
@@ -236,6 +236,10 @@
}
}
+ void setPositionAppliesWithResizeInTransaction(boolean recoveringMemory) {
+ mSurfaceControl.setPositionAppliesWithResize();
+ }
+
void setMatrixInTransaction(float dsdx, float dtdx, float dsdy, float dtdy,
boolean recoveringMemory) {
try {
@@ -554,6 +558,13 @@
}
@Override
+ public void setPositionAppliesWithResize() {
+ if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setPositionAppliesWithResize(): OLD: "
+ + this + ". Called by" + Debug.getCallers(9));
+ super.setPositionAppliesWithResize();
+ }
+
+ @Override
public void setSize(int w, int h) {
if (w != mSize.x || h != mSize.y) {
if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setSize(" + w + "," + h + "): OLD:"