summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jim Miller <jaggies@google.com> 2011-06-13 19:56:32 -0700
committer Jim Miller <jaggies@google.com> 2011-06-13 23:57:31 -0700
commit70832a3d77d90f09fb7ba27612c9cbec6a92abe6 (patch)
treef9fc05173a4959e2337eff1aad3d235d772b553c
parentfcc79771f092f34505b1accb80365cbcaa379667 (diff)
Some tuning for MultiWaveView animations and assets:
- allow individual chevrons to be specified for (top, bottom, left, right). - move ring to pressed position (currently w/o animation) - add top/bottom chevron handling and refactor code accordingly. - constrain drag handle to the ring Change-Id: I859b2d03d8f0397c68b87a8ee15df20d55c9552c
-rw-r--r--api/current.txt18
-rw-r--r--core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java113
-rw-r--r--core/java/com/android/internal/widget/multiwaveview/Tweener.java7
-rw-r--r--core/res/res/drawable-hdpi/ic_lockscreen_chevron_down.pngbin0 -> 688 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lockscreen_chevron_up.pngbin0 -> 698 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lockscreen_chevron_down.pngbin0 -> 538 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lockscreen_chevron_up.pngbin0 -> 536 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lockscreen_chevron_down.pngbin0 -> 859 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lockscreen_chevron_up.pngbin0 -> 845 bytes
-rw-r--r--core/res/res/layout/keyguard_screen_tab_unlock.xml1
-rw-r--r--core/res/res/layout/keyguard_screen_tab_unlock_land.xml3
-rwxr-xr-xcore/res/res/values/attrs.xml10
-rw-r--r--core/res/res/values/public.xml2
-rw-r--r--policy/src/com/android/internal/policy/impl/LockScreen.java6
14 files changed, 97 insertions, 63 deletions
diff --git a/api/current.txt b/api/current.txt
index acea3e79e6e0..ed5f1562bd11 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -259,6 +259,7 @@ package android {
field public static final int borderlessButtonStyle = 16843563; // 0x101032b
field public static final int bottom = 16843184; // 0x10101b0
field public static final int bottomBright = 16842957; // 0x10100cd
+ field public static final int bottomChevronDrawable = 16843661; // 0x101038d
field public static final int bottomDark = 16842953; // 0x10100c9
field public static final int bottomLeftRadius = 16843179; // 0x10101ab
field public static final int bottomMedium = 16842958; // 0x10100ce
@@ -425,7 +426,7 @@ package android {
field public static final int fastScrollTextColor = 16843609; // 0x1010359
field public static final int fastScrollThumbDrawable = 16843574; // 0x1010336
field public static final int fastScrollTrackDrawable = 16843577; // 0x1010339
- field public static final int feedbackCount = 16843665; // 0x1010391
+ field public static final int feedbackCount = 16843667; // 0x1010393
field public static final int fillAfter = 16843197; // 0x10101bd
field public static final int fillBefore = 16843196; // 0x10101bc
field public static final int fillEnabled = 16843343; // 0x101024f
@@ -488,12 +489,12 @@ package android {
field public static final int headerDividersEnabled = 16843310; // 0x101022e
field public static final int height = 16843093; // 0x1010155
field public static final int hint = 16843088; // 0x1010150
- field public static final int hitRadius = 16843662; // 0x101038e
+ field public static final int hitRadius = 16843664; // 0x1010390
field public static final int homeAsUpIndicator = 16843531; // 0x101030b
field public static final int homeLayout = 16843549; // 0x101031d
field public static final int horizontalDivider = 16843053; // 0x101012d
field public static final int horizontalGap = 16843327; // 0x101023f
- field public static final int horizontalOffset = 16843667; // 0x1010393
+ field public static final int horizontalOffset = 16843669; // 0x1010395
field public static final int horizontalScrollViewStyle = 16843603; // 0x1010353
field public static final int horizontalSpacing = 16843028; // 0x1010114
field public static final int host = 16842792; // 0x1010028
@@ -686,7 +687,7 @@ package android {
field public static final int orderingFromXml = 16843239; // 0x10101e7
field public static final int orientation = 16842948; // 0x10100c4
field public static final int outAnimation = 16843128; // 0x1010178
- field public static final int outerRadius = 16843661; // 0x101038d
+ field public static final int outerRadius = 16843663; // 0x101038f
field public static final int overScrollFooter = 16843459; // 0x10102c3
field public static final int overScrollHeader = 16843458; // 0x10102c2
field public static final int overScrollMode = 16843457; // 0x10102c1
@@ -851,7 +852,7 @@ package android {
field public static final int smallIcon = 16843422; // 0x101029e
field public static final int smallScreens = 16843396; // 0x1010284
field public static final int smoothScrollbar = 16843313; // 0x1010231
- field public static final int snapMargin = 16843664; // 0x1010390
+ field public static final int snapMargin = 16843666; // 0x1010392
field public static final int soundEffectsEnabled = 16843285; // 0x1010215
field public static final int spacing = 16843027; // 0x1010113
field public static final int spinnerDropDownItemStyle = 16842887; // 0x1010087
@@ -1006,6 +1007,7 @@ package android {
field public static final int toYScale = 16843205; // 0x10101c5
field public static final int top = 16843182; // 0x10101ae
field public static final int topBright = 16842955; // 0x10100cb
+ field public static final int topChevronDrawable = 16843660; // 0x101038c
field public static final int topDark = 16842951; // 0x10100c7
field public static final int topLeftRadius = 16843177; // 0x10101a9
field public static final int topOffset = 16843352; // 0x1010258
@@ -1035,10 +1037,10 @@ package android {
field public static final int verticalCorrection = 16843322; // 0x101023a
field public static final int verticalDivider = 16843054; // 0x101012e
field public static final int verticalGap = 16843328; // 0x1010240
- field public static final int verticalOffset = 16843666; // 0x1010392
+ field public static final int verticalOffset = 16843668; // 0x1010394
field public static final int verticalScrollbarPosition = 16843572; // 0x1010334
field public static final int verticalSpacing = 16843029; // 0x1010115
- field public static final int vibrationDuration = 16843663; // 0x101038f
+ field public static final int vibrationDuration = 16843665; // 0x1010391
field public static final int visibility = 16842972; // 0x10100dc
field public static final int visible = 16843156; // 0x1010194
field public static final int vmSafeMode = 16843448; // 0x10102b8
@@ -1055,7 +1057,7 @@ package android {
field public static final int wallpaperIntraOpenExitAnimation = 16843416; // 0x1010298
field public static final int wallpaperOpenEnterAnimation = 16843411; // 0x1010293
field public static final int wallpaperOpenExitAnimation = 16843412; // 0x1010294
- field public static final int waveDrawable = 16843660; // 0x101038c
+ field public static final int waveDrawable = 16843662; // 0x101038e
field public static final int webTextViewStyle = 16843449; // 0x10102b9
field public static final int webViewStyle = 16842885; // 0x1010085
field public static final int weekDayTextAppearance = 16843592; // 0x1010348
diff --git a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
index 026ad2763d99..1e9882796f6d 100644
--- a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
+++ b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
@@ -134,18 +134,26 @@ public class MultiWaveView extends View implements AnimatorUpdateListener {
mTapRadius = mHandleDrawable.getWidth()/2;
mOuterRing = new TargetDrawable(res, a.getDrawable(R.styleable.MultiWaveView_waveDrawable));
- // Read animation drawables
+ // Read chevron animation drawables
Drawable leftChevron = a.getDrawable(R.styleable.MultiWaveView_leftChevronDrawable);
- if (leftChevron != null) {
- for (int i = 0; i < mFeedbackCount; i++) {
- mChevronDrawables.add(new TargetDrawable(res, leftChevron));
- }
+ for (int i = 0; i < mFeedbackCount; i++) {
+ mChevronDrawables.add(
+ leftChevron != null ? new TargetDrawable(res, leftChevron) : null);
}
Drawable rightChevron = a.getDrawable(R.styleable.MultiWaveView_rightChevronDrawable);
- if (rightChevron != null) {
- for (int i = 0; i < mFeedbackCount; i++) {
- mChevronDrawables.add(new TargetDrawable(res, rightChevron));
- }
+ for (int i = 0; i < mFeedbackCount; i++) {
+ mChevronDrawables.add(
+ rightChevron != null ? new TargetDrawable(res, rightChevron) : null);
+ }
+ Drawable topChevron = a.getDrawable(R.styleable.MultiWaveView_topChevronDrawable);
+ for (int i = 0; i < mFeedbackCount; i++) {
+ mChevronDrawables.add(
+ topChevron != null ? new TargetDrawable(res, topChevron) : null);
+ }
+ Drawable bottomChevron = a.getDrawable(R.styleable.MultiWaveView_bottomChevronDrawable);
+ for (int i = 0; i < mFeedbackCount; i++) {
+ mChevronDrawables.add(
+ bottomChevron != null ? new TargetDrawable(res, bottomChevron) : null);
}
// Read array of target drawables
@@ -190,7 +198,6 @@ public class MultiWaveView extends View implements AnimatorUpdateListener {
private void switchToState(int state, float x, float y) {
switch (state) {
case STATE_IDLE:
- stopChevronAnimation();
deactivateTargets();
mHandleDrawable.setState(TargetDrawable.STATE_INACTIVE);
break;
@@ -221,33 +228,32 @@ public class MultiWaveView extends View implements AnimatorUpdateListener {
* followed by right chevrons.
*/
private void startChevronAnimation() {
- final int icons = mChevronDrawables.size();
- for (Tweener tween : mChevronAnimations) {
- tween.animator.cancel();
- }
- for (int i = 0; i < icons; i++) {
- TargetDrawable icon = mChevronDrawables.get(i);
- icon.setY(mWaveCenterY);
- icon.setAlpha(1.0f);
- mChevronAnimations.clear();
- int delay = (int) (Math.abs(0.5f + i - icons / 2) * CHEVRON_INCREMENTAL_DELAY);
- if (i < icons/2) {
- // Left chevrons
- icon.setX(mWaveCenterX - mHandleDrawable.getWidth() / 2);
- mChevronAnimations.add(Tweener.to(icon, CHEVRON_ANIMATION_DURATION,
- "ease", mChevronAnimationInterpolator,
- "delay", delay,
- "x", mWaveCenterX - mOuterRadius,
- "alpha", 0.0f,
- "onUpdate", this));
- } else {
- // Right chevrons
- icon.setX(mWaveCenterX + mHandleDrawable.getWidth() / 2);
+ final float r = mHandleDrawable.getWidth() / 2;
+ final float from[][] = {
+ {mWaveCenterX - r, mWaveCenterY}, // left
+ {mWaveCenterX + r, mWaveCenterY}, // right
+ {mWaveCenterX, mWaveCenterY - r}, // top
+ {mWaveCenterX, mWaveCenterY + r} }; // bottom
+ final float to[][] = {
+ {mWaveCenterX - mOuterRadius, mWaveCenterY}, // left
+ {mWaveCenterX + mOuterRadius, mWaveCenterY}, // right
+ {mWaveCenterX, mWaveCenterY - mOuterRadius}, // top
+ {mWaveCenterX, mWaveCenterY + mOuterRadius} }; // bottom
+
+ mChevronAnimations.clear();
+ for (int direction = 0; direction < 4; direction++) {
+ for (int count = 0; count < mFeedbackCount; count++) {
+ int delay = count * CHEVRON_INCREMENTAL_DELAY;
+ final TargetDrawable icon = mChevronDrawables.get(direction*mFeedbackCount + count);
+ if (icon == null) {
+ continue;
+ }
mChevronAnimations.add(Tweener.to(icon, CHEVRON_ANIMATION_DURATION,
"ease", mChevronAnimationInterpolator,
"delay", delay,
- "x", mWaveCenterX + mOuterRadius,
- "alpha", 0.0f,
+ "x", new float[] { from[direction][0], to[direction][0] },
+ "y", new float[] { from[direction][1], to[direction][1] },
+ "alpha", new float[] {1.0f, 0.0f},
"onUpdate", this));
}
}
@@ -330,8 +336,6 @@ public class MultiWaveView extends View implements AnimatorUpdateListener {
if (targetHit) {
mTargetDrawables.get(activeTarget).setState(TargetDrawable.STATE_ACTIVE);
}
-
- stopChevronAnimation();
}
private void hideTargets(boolean animate) {
@@ -392,11 +396,12 @@ public class MultiWaveView extends View implements AnimatorUpdateListener {
Resources res = getContext().getResources();
TypedArray array = res.obtainTypedArray(resourceId);
int count = array.length();
- mTargetDrawables = new ArrayList<TargetDrawable>(count);
+ ArrayList<TargetDrawable> targetDrawables = new ArrayList<TargetDrawable>(count);
for (int i = 0; i < count; i++) {
Drawable drawable = array.getDrawable(i);
- mTargetDrawables.add(new TargetDrawable(res, drawable));
+ targetDrawables.add(new TargetDrawable(res, drawable));
}
+ mTargetDrawables = targetDrawables;
}
/**
@@ -472,12 +477,19 @@ public class MultiWaveView extends View implements AnimatorUpdateListener {
return handled ? true : super.onTouchEvent(event);
}
+ private void moveHandleTo(float x, float y, boolean animate) {
+ // TODO: animate the handle based on the current state/position
+ mHandleDrawable.setX(x);
+ mHandleDrawable.setY(y);
+ }
+
private void handleDown(float x, float y) {
final float dx = x - mWaveCenterX;
final float dy = y - mWaveCenterY;
if (dist2(dx,dy) <= square(mTapRadius)) {
if (DEBUG) Log.v(TAG, "** Handle HIT");
switchToState(STATE_FIRST_TOUCH, x, y);
+ moveHandleTo(x, y, false);
mDragging = true;
} else {
mDragging = false;
@@ -528,11 +540,14 @@ public class MultiWaveView extends View implements AnimatorUpdateListener {
best = dist2;
}
}
+ x = limitX;
+ y = limitY;
}
if (activeTarget != -1) {
switchToState(STATE_SNAP, x,y);
- mHandleDrawable.setX(singleTarget ? limitX : mTargetDrawables.get(activeTarget).getX());
- mHandleDrawable.setY(singleTarget ? limitY : mTargetDrawables.get(activeTarget).getY());
+ float newX = singleTarget ? limitX : mTargetDrawables.get(activeTarget).getX();
+ float newY = singleTarget ? limitY : mTargetDrawables.get(activeTarget).getY();
+ moveHandleTo(newX, newY, false);
TargetDrawable currentTarget = mTargetDrawables.get(activeTarget);
if (currentTarget.hasState(TargetDrawable.STATE_FOCUSED)) {
currentTarget.setState(TargetDrawable.STATE_FOCUSED);
@@ -540,8 +555,7 @@ public class MultiWaveView extends View implements AnimatorUpdateListener {
}
} else {
switchToState(STATE_TRACKING, x, y);
- mHandleDrawable.setX(x);
- mHandleDrawable.setY(y);
+ moveHandleTo(x, y, false);
mHandleDrawable.setAlpha(1.0f);
}
// Draw handle outside parent's bounds
@@ -577,8 +591,7 @@ public class MultiWaveView extends View implements AnimatorUpdateListener {
mWaveCenterX = mHorizontalOffset + Math.max(width, mOuterRing.getWidth() ) / 2;
mWaveCenterY = mVerticalOffset + Math.max(height, mOuterRing.getHeight()) / 2;
- mHandleDrawable.setX(mWaveCenterX);
- mHandleDrawable.setY(mWaveCenterY);
+ moveHandleTo(mWaveCenterX, mWaveCenterY, false);
mOuterRing.setX(mWaveCenterX);
mOuterRing.setY(Math.max(mWaveCenterY, mWaveCenterY));
mOuterRing.setAlpha(0.0f);
@@ -609,7 +622,9 @@ public class MultiWaveView extends View implements AnimatorUpdateListener {
private void hideChevrons() {
for (TargetDrawable chevron : mChevronDrawables) {
- chevron.setAlpha(0.0f);
+ if (chevron != null) {
+ chevron.setAlpha(0.0f);
+ }
}
}
@@ -617,10 +632,14 @@ public class MultiWaveView extends View implements AnimatorUpdateListener {
protected void onDraw(Canvas canvas) {
mOuterRing.draw(canvas);
for (TargetDrawable target : mTargetDrawables) {
- target.draw(canvas);
+ if (target != null) {
+ target.draw(canvas);
+ }
}
for (TargetDrawable target : mChevronDrawables) {
- target.draw(canvas);
+ if (target != null) {
+ target.draw(canvas);
+ }
}
mHandleDrawable.draw(canvas);
}
diff --git a/core/java/com/android/internal/widget/multiwaveview/Tweener.java b/core/java/com/android/internal/widget/multiwaveview/Tweener.java
index c2746d97a323..0cff00a514ab 100644
--- a/core/java/com/android/internal/widget/multiwaveview/Tweener.java
+++ b/core/java/com/android/internal/widget/multiwaveview/Tweener.java
@@ -63,14 +63,15 @@ class Tweener {
delay = ((Number) value).longValue();
} else if ("syncWith".equals(key)) {
// TODO
- } else if (value instanceof Number[]) {
- // TODO: support Tween.from()
+ } else if (value instanceof float[]) {
+ props.add(PropertyValuesHolder.ofFloat(key,
+ ((float[])value)[0], ((float[])value)[1]));
} else if (value instanceof Number) {
float floatValue = ((Number)value).floatValue();
props.add(PropertyValuesHolder.ofFloat(key, floatValue));
} else {
throw new IllegalArgumentException(
- "Bad argument for key \"" + key + "with value" + value);
+ "Bad argument for key \"" + key + "\" with value " + value.getClass());
}
}
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_chevron_down.png b/core/res/res/drawable-hdpi/ic_lockscreen_chevron_down.png
new file mode 100644
index 000000000000..620844ec374f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_chevron_down.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_chevron_up.png b/core/res/res/drawable-hdpi/ic_lockscreen_chevron_up.png
new file mode 100644
index 000000000000..4ffa833b93cf
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_chevron_up.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_chevron_down.png b/core/res/res/drawable-mdpi/ic_lockscreen_chevron_down.png
new file mode 100644
index 000000000000..d3cfd17ea104
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_chevron_down.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_chevron_up.png b/core/res/res/drawable-mdpi/ic_lockscreen_chevron_up.png
new file mode 100644
index 000000000000..35aca4e82450
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_chevron_up.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_chevron_down.png b/core/res/res/drawable-xhdpi/ic_lockscreen_chevron_down.png
new file mode 100644
index 000000000000..c655d93b0cc7
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_chevron_down.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_chevron_up.png b/core/res/res/drawable-xhdpi/ic_lockscreen_chevron_up.png
new file mode 100644
index 000000000000..53794fde8cf7
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_chevron_up.png
Binary files differ
diff --git a/core/res/res/layout/keyguard_screen_tab_unlock.xml b/core/res/res/layout/keyguard_screen_tab_unlock.xml
index 24891dce7882..7ae357a86006 100644
--- a/core/res/res/layout/keyguard_screen_tab_unlock.xml
+++ b/core/res/res/layout/keyguard_screen_tab_unlock.xml
@@ -176,7 +176,6 @@
android:snapMargin="@*android:dimen/multiwaveview_snap_margin"
android:hitRadius="@*android:dimen/multiwaveview_hit_radius"
android:vibrationDuration="20"
- android:leftChevronDrawable="@drawable/ic_lockscreen_chevron_left"
android:rightChevronDrawable="@drawable/ic_lockscreen_chevron_right"
android:feedbackCount="3"
android:horizontalOffset="0dip"
diff --git a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
index 02994a9bf841..df29a4b3c09e 100644
--- a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
+++ b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
@@ -176,8 +176,7 @@
android:snapMargin="@*android:dimen/multiwaveview_snap_margin"
android:hitRadius="@*android:dimen/multiwaveview_hit_radius"
android:vibrationDuration="20"
- android:leftChevronDrawable="@drawable/ic_lockscreen_chevron_left"
- android:rightChevronDrawable="@drawable/ic_lockscreen_chevron_right"
+ android:topChevronDrawable="@drawable/ic_lockscreen_chevron_up"
android:feedbackCount="3"
android:horizontalOffset="60dip"
android:verticalOffset="0dip"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index acfdfc90cf6c..5d357c55421d 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -5019,12 +5019,18 @@
<!-- Sets a drawable as the drag center. -->
<attr name="handleDrawable" format="reference" />
- <!-- Drawable to use for chevron animation on the left. -->
+ <!-- Drawable to use for chevron animation on the left. May be null. -->
<attr name="leftChevronDrawable" format="reference" />
- <!-- Drawable to use for chevron animation on the right. -->
+ <!-- Drawable to use for chevron animation on the right. May be null. -->
<attr name="rightChevronDrawable" format="reference" />
+ <!-- Drawable to use for chevron animation on the top. May be null. -->
+ <attr name="topChevronDrawable" format="reference" />
+
+ <!-- Drawable to use for chevron animation on the bottom. May be null. -->
+ <attr name="bottomChevronDrawable" format="reference" />
+
<!-- Drawable to use for wave ripple animation. -->
<attr name="waveDrawable" format="reference" />
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 4108c1b9a5ea..17b23da054a2 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1756,6 +1756,8 @@
<public type="attr" name="handleDrawable" />
<public type="attr" name="leftChevronDrawable" />
<public type="attr" name="rightChevronDrawable" />
+ <public type="attr" name="topChevronDrawable" />
+ <public type="attr" name="bottomChevronDrawable" />
<public type="attr" name="waveDrawable" />
<public type="attr" name="outerRadius" />
<public type="attr" name="hitRadius" />
diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java
index 0178395be45f..c7dc399d1663 100644
--- a/policy/src/com/android/internal/policy/impl/LockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/LockScreen.java
@@ -710,11 +710,17 @@ class LockScreen extends LinearLayout implements KeyguardScreen,
if (mEnergyWave != null) {
mEnergyWave.reset();
}
+ if (mMultiWaveView != null) {
+ mMultiWaveView.reset(false);
+ }
}
/** {@inheritDoc} */
public void onResume() {
resetStatusInfo(mUpdateMonitor);
+ if (mMultiWaveView != null) {
+ mMultiWaveView.ping();
+ }
}
/** {@inheritDoc} */