Removed unused code, minor fixes

This commit is contained in:
Nite 2021-02-09 19:49:26 +01:00
parent 1b9b127424
commit c4ea2086d2
No known key found for this signature in database
GPG Key ID: 1D1AD59B1C6386C1
42 changed files with 22 additions and 6178 deletions

View File

@ -1,13 +0,0 @@
apply from: bootstrap.androidModule
android {
lintOptions {
baselineFile file("lint-baseline.xml")
abortOnError true
}
}
dependencies {
implementation "androidx.appcompat:appcompat-resources:1.2.0"
implementation other.timber
}

View File

@ -1,246 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<issues format="4" by="lint 2.3.3">
<issue
id="InlinedApi"
message="Field requires API level 17 (current min is 14): `android.view.View#LAYOUT_DIRECTION_RTL`"
errorLine1=" if (mSlideDrawable != null) mSlideDrawable.setIsRtl(layoutDirection == LAYOUT_DIRECTION_RTL);"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/net/simonvt/menudrawer/MenuDrawer.java"
line="882"
column="80"/>
</issue>
<issue
id="InlinedApi"
message="Field requires API level 17 (current min is 14): `android.view.View#LAYOUT_DIRECTION_RTL`"
errorLine1=" mSlideDrawable.setIsRtl(ViewHelper.getLayoutDirection(this) == LAYOUT_DIRECTION_RTL);"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/net/simonvt/menudrawer/MenuDrawer.java"
line="1325"
column="72"/>
</issue>
<issue
id="OldTargetApi"
message="Not targeting the latest versions of Android; compatibility modes apply. Consider testing and updating this version. Consult the `android.os.Build.VERSION_CODES` javadoc for details."
errorLine1=" &lt;uses-sdk android:minSdkVersion=&quot;7&quot; android:targetSdkVersion=&quot;16&quot; />"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/AndroidManifest.xml"
line="7"
column="41"/>
</issue>
<issue
id="GradleOverrides"
message="This `minSdkVersion` value (`7`) is not used; it is always overridden by the value specified in the Gradle build script (`14`)"
errorLine1=" &lt;uses-sdk android:minSdkVersion=&quot;7&quot; android:targetSdkVersion=&quot;16&quot; />"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/AndroidManifest.xml"
line="7"
column="15"/>
</issue>
<issue
id="GradleOverrides"
message="This `targetSdkVersion` value (`16`) is not used; it is always overridden by the value specified in the Gradle build script (`22`)"
errorLine1=" &lt;uses-sdk android:minSdkVersion=&quot;7&quot; android:targetSdkVersion=&quot;16&quot; />"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/AndroidManifest.xml"
line="7"
column="41"/>
</issue>
<issue
id="ParcelClassLoader"
message="Using the default class loader will not work if you are restoring your own classes. Consider using for example `readBundle(getClass().getClassLoader())` instead."
errorLine1=" mState = in.readBundle();"
errorLine2=" ~~~~~~~~~~~~">
<location
file="src/main/java/net/simonvt/menudrawer/MenuDrawer.java"
line="1630"
column="25"/>
</issue>
<issue
id="ObsoleteSdkInt"
message="Unnecessary; SDK_INT is never &lt; 14"
errorLine1=" if (mUsesCompat &amp;&amp; Build.VERSION.SDK_INT &lt; Build.VERSION_CODES.ICE_CREAM_SANDWICH) {"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/net/simonvt/menudrawer/compat/ActionBarHelper.java"
line="41"
column="28"/>
</issue>
<issue
id="ObsoleteSdkInt"
message="Unnecessary; SDK_INT is always >= 14"
errorLine1=" } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/net/simonvt/menudrawer/compat/ActionBarHelper.java"
line="43"
column="20"/>
</issue>
<issue
id="ObsoleteSdkInt"
message="Unnecessary; SDK_INT is never &lt; 14"
errorLine1=" if (mUsesCompat &amp;&amp; Build.VERSION.SDK_INT &lt; Build.VERSION_CODES.ICE_CREAM_SANDWICH) {"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/net/simonvt/menudrawer/compat/ActionBarHelper.java"
line="51"
column="28"/>
</issue>
<issue
id="ObsoleteSdkInt"
message="Unnecessary; SDK_INT is always >= 14"
errorLine1=" } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/net/simonvt/menudrawer/compat/ActionBarHelper.java"
line="53"
column="20"/>
</issue>
<issue
id="ObsoleteSdkInt"
message="Unnecessary; SDK_INT is never &lt; 14"
errorLine1=" if (mUsesCompat &amp;&amp; Build.VERSION.SDK_INT &lt; Build.VERSION_CODES.ICE_CREAM_SANDWICH) {"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/net/simonvt/menudrawer/compat/ActionBarHelper.java"
line="59"
column="28"/>
</issue>
<issue
id="ObsoleteSdkInt"
message="Unnecessary; SDK_INT is always >= 14"
errorLine1=" } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/net/simonvt/menudrawer/compat/ActionBarHelper.java"
line="61"
column="20"/>
</issue>
<issue
id="ObsoleteSdkInt"
message="Unnecessary; SDK_INT is never &lt; 14"
errorLine1=" if (mUsesCompat &amp;&amp; Build.VERSION.SDK_INT &lt; Build.VERSION_CODES.ICE_CREAM_SANDWICH) {"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/net/simonvt/menudrawer/compat/ActionBarHelper.java"
line="67"
column="28"/>
</issue>
<issue
id="ObsoleteSdkInt"
message="Unnecessary; SDK_INT is always >= 14"
errorLine1=" } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/net/simonvt/menudrawer/compat/ActionBarHelper.java"
line="69"
column="20"/>
</issue>
<issue
id="ObsoleteSdkInt"
message="Unnecessary; SDK_INT is never &lt; 14"
errorLine1=" if (mUsesCompat &amp;&amp; Build.VERSION.SDK_INT &lt; Build.VERSION_CODES.ICE_CREAM_SANDWICH) {"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/net/simonvt/menudrawer/compat/ActionBarHelper.java"
line="77"
column="28"/>
</issue>
<issue
id="ObsoleteSdkInt"
message="Unnecessary; SDK_INT is always >= 14"
errorLine1=" } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/net/simonvt/menudrawer/compat/ActionBarHelper.java"
line="79"
column="20"/>
</issue>
<issue
id="ObsoleteSdkInt"
message="Unnecessary; SDK_INT is always >= 14"
errorLine1=" if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/net/simonvt/menudrawer/DraggableDrawer.java"
line="572"
column="13"/>
</issue>
<issue
id="ObsoleteSdkInt"
message="Unnecessary; SDK_INT is always >= 14"
errorLine1=" if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/net/simonvt/menudrawer/DraggableDrawer.java"
line="580"
column="13"/>
</issue>
<issue
id="ObsoleteSdkInt"
message="Unnecessary; SDK_INT is always >= 14"
errorLine1=" if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/net/simonvt/menudrawer/DraggableDrawer.java"
line="588"
column="13"/>
</issue>
<issue
id="ObsoleteSdkInt"
message="Unnecessary; SDK_INT is always >= 14"
errorLine1=" if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/net/simonvt/menudrawer/DraggableDrawer.java"
line="596"
column="13"/>
</issue>
<issue
id="FloatMath"
message="Use `java.lang.Math#sqrt` instead of `android.util.FloatMath#sqrt()` since it is faster as of API 8"
errorLine1=" float hyp = FloatMath.sqrt(dx * dx + dy * dy);"
errorLine2=" ~~~~~~~~~~~~~~">
<location
file="src/main/java/net/simonvt/menudrawer/Scroller.java"
line="374"
column="25"/>
</issue>
<issue
id="FloatMath"
message="Use `java.lang.Math#sqrt` instead of `android.util.FloatMath#sqrt()` since it is faster as of API 8"
errorLine1=" float velocity = FloatMath.sqrt(velocityX * velocityX + velocityY * velocityY);"
errorLine2=" ~~~~~~~~~~~~~~">
<location
file="src/main/java/net/simonvt/menudrawer/Scroller.java"
line="391"
column="26"/>
</issue>
</issues>

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.simonvt.menudrawer"
android:versionCode="6"
android:versionName="3.0.2">
</manifest>

View File

@ -1,99 +0,0 @@
package net.simonvt.menudrawer;
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.widget.FrameLayout;
/**
* FrameLayout which caches the hardware layer if available.
* <p/>
* If it's not posted twice the layer either wont be built on start, or it'll be built twice.
*/
class BuildLayerFrameLayout extends FrameLayout {
private boolean mChanged;
private boolean mHardwareLayersEnabled = true;
private boolean mAttached;
private boolean mFirst = true;
public BuildLayerFrameLayout(Context context) {
super(context);
if (MenuDrawer.USE_TRANSLATIONS) {
setLayerType(LAYER_TYPE_HARDWARE, null);
}
}
public BuildLayerFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
if (MenuDrawer.USE_TRANSLATIONS) {
setLayerType(LAYER_TYPE_HARDWARE, null);
}
}
public BuildLayerFrameLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if (MenuDrawer.USE_TRANSLATIONS) {
setLayerType(LAYER_TYPE_HARDWARE, null);
}
}
void setHardwareLayersEnabled(boolean enabled) {
mHardwareLayersEnabled = enabled;
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mAttached = true;
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mAttached = false;
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (MenuDrawer.USE_TRANSLATIONS && mHardwareLayersEnabled) {
post(new Runnable() {
@Override
public void run() {
mChanged = true;
invalidate();
}
});
}
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (mChanged && MenuDrawer.USE_TRANSLATIONS) {
post(new Runnable() {
@Override
public void run() {
if (mAttached) {
final int layerType = getLayerType();
// If it's already a hardware layer, it'll be built anyway.
if (layerType != LAYER_TYPE_HARDWARE || mFirst) {
mFirst = false;
setLayerType(LAYER_TYPE_HARDWARE, null);
buildLayer();
setLayerType(LAYER_TYPE_NONE, null);
}
}
}
});
mChanged = false;
}
}
}

View File

@ -1,170 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.simonvt.menudrawer;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
/**
* A specialized Drawable that fills the Canvas with a specified color.
* Note that a ColorDrawable ignores the ColorFilter.
* <p/>
* <p>It can be defined in an XML file with the <code>&lt;color></code> element.</p>
*
* @attr ref android.R.styleable#ColorDrawable_color
*/
class ColorDrawable extends Drawable {
private ColorState mState;
private final Paint mPaint = new Paint();
/** Creates a new black ColorDrawable. */
public ColorDrawable() {
this(null);
}
/**
* Creates a new ColorDrawable with the specified color.
*
* @param color The color to draw.
*/
public ColorDrawable(int color) {
this(null);
setColor(color);
}
private ColorDrawable(ColorState state) {
mState = new ColorState(state);
}
@Override
public int getChangingConfigurations() {
return super.getChangingConfigurations() | mState.mChangingConfigurations;
}
@Override
public void draw(Canvas canvas) {
if ((mState.mUseColor >>> 24) != 0) {
mPaint.setColor(mState.mUseColor);
canvas.drawRect(getBounds(), mPaint);
}
}
/**
* Gets the drawable's color value.
*
* @return int The color to draw.
*/
public int getColor() {
return mState.mUseColor;
}
/**
* Sets the drawable's color value. This action will clobber the results of prior calls to
* {@link #setAlpha(int)} on this object, which side-affected the underlying color.
*
* @param color The color to draw.
*/
public void setColor(int color) {
if (mState.mBaseColor != color || mState.mUseColor != color) {
invalidateSelf();
mState.mBaseColor = mState.mUseColor = color;
}
}
/**
* Returns the alpha value of this drawable's color.
*
* @return A value between 0 and 255.
*/
public int getAlpha() {
return mState.mUseColor >>> 24;
}
/**
* Sets the color's alpha value.
*
* @param alpha The alpha value to set, between 0 and 255.
*/
public void setAlpha(int alpha) {
alpha += alpha >> 7; // make it 0..256
int baseAlpha = mState.mBaseColor >>> 24;
int useAlpha = baseAlpha * alpha >> 8;
int oldUseColor = mState.mUseColor;
mState.mUseColor = (mState.mBaseColor << 8 >>> 8) | (useAlpha << 24);
if (oldUseColor != mState.mUseColor) {
invalidateSelf();
}
}
/**
* Setting a color filter on a ColorDrawable has no effect.
*
* @param colorFilter Ignore.
*/
public void setColorFilter(ColorFilter colorFilter) {
}
public int getOpacity() {
switch (mState.mUseColor >>> 24) {
case 255:
return PixelFormat.OPAQUE;
case 0:
return PixelFormat.TRANSPARENT;
}
return PixelFormat.TRANSLUCENT;
}
@Override
public ConstantState getConstantState() {
mState.mChangingConfigurations = getChangingConfigurations();
return mState;
}
static final class ColorState extends ConstantState {
int mBaseColor; // base color, independent of setAlpha()
int mUseColor; // basecolor modulated by setAlpha()
int mChangingConfigurations;
ColorState(ColorState state) {
if (state != null) {
mBaseColor = state.mBaseColor;
mUseColor = state.mUseColor;
}
}
@Override
public Drawable newDrawable() {
return new ColorDrawable(this);
}
@Override
public Drawable newDrawable(Resources res) {
return new ColorDrawable(this);
}
@Override
public int getChangingConfigurations() {
return mChangingConfigurations;
}
}
}

View File

@ -1,619 +0,0 @@
package net.simonvt.menudrawer;
import android.app.Activity;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcelable;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.animation.Interpolator;
public abstract class DraggableDrawer extends MenuDrawer {
/**
* Key used when saving menu visibility state.
*/
private static final String STATE_MENU_VISIBLE = "net.simonvt.menudrawer.MenuDrawer.menuVisible";
/**
* Interpolator used for peeking at the drawer.
*/
private static final Interpolator PEEK_INTERPOLATOR = new PeekInterpolator();
/**
* The maximum alpha of the dark menu overlay used for dimming the menu.
*/
protected static final int MAX_MENU_OVERLAY_ALPHA = 185;
/**
* Default delay from {@link #peekDrawer()} is called until first animation is run.
*/
private static final long DEFAULT_PEEK_START_DELAY = 5000;
/**
* Default delay between each subsequent animation, after {@link #peekDrawer()} has been called.
*/
private static final long DEFAULT_PEEK_DELAY = 10000;
/**
* The duration of the peek animation.
*/
protected static final int PEEK_DURATION = 5000;
/**
* Distance in dp from closed position from where the drawer is considered closed with regards to touch events.
*/
private static final int CLOSE_ENOUGH = 3;
protected static final int INVALID_POINTER = -1;
/**
* Slop before starting a drag.
*/
protected int mTouchSlop;
/**
* Runnable used when the peek animation is running.
*/
protected final Runnable mPeekRunnable = new Runnable() {
@Override
public void run() {
peekDrawerInvalidate();
}
};
/**
* Runnable used when animating the drawer open/closed.
*/
private final Runnable mDragRunnable = new Runnable() {
@Override
public void run() {
postAnimationInvalidate();
}
};
/**
* Indicates whether the drawer is currently being dragged.
*/
protected boolean mIsDragging;
/**
* The current pointer id.
*/
protected int mActivePointerId = INVALID_POINTER;
/**
* The initial X position of a drag.
*/
protected float mInitialMotionX;
/**
* The initial Y position of a drag.
*/
protected float mInitialMotionY;
/**
* The last X position of a drag.
*/
protected float mLastMotionX = -1;
/**
* The last Y position of a drag.
*/
protected float mLastMotionY = -1;
/**
* Default delay between each subsequent animation, after {@link #peekDrawer()} has been called.
*/
protected long mPeekDelay;
/**
* Scroller used for the peek drawer animation.
*/
protected Scroller mPeekScroller;
/**
* Velocity tracker used when animating the drawer open/closed after a drag.
*/
protected VelocityTracker mVelocityTracker;
/**
* Maximum velocity allowed when animating the drawer open/closed.
*/
protected int mMaxVelocity;
/**
* Indicates whether the menu should be offset when dragging the drawer.
*/
protected boolean mOffsetMenu = true;
/**
* Distance in px from closed position from where the drawer is considered closed with regards to touch events.
*/
protected int mCloseEnough;
/**
* Runnable used for first call to {@link #startPeek()} after {@link #peekDrawer()} has been called.
*/
private Runnable mPeekStartRunnable;
/**
* Scroller used when animating the drawer open/closed.
*/
private Scroller mScroller;
/**
* Indicates whether the current layer type is {@link android.view.View#LAYER_TYPE_HARDWARE}.
*/
protected boolean mLayerTypeHardware;
DraggableDrawer(Activity activity, int dragMode) {
super(activity, dragMode);
}
public DraggableDrawer(Context context) {
super(context);
}
public DraggableDrawer(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DraggableDrawer(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void initDrawer(Context context, AttributeSet attrs, int defStyle) {
super.initDrawer(context, attrs, defStyle);
final ViewConfiguration configuration = ViewConfiguration.get(context);
mTouchSlop = configuration.getScaledTouchSlop();
mMaxVelocity = configuration.getScaledMaximumFlingVelocity();
mScroller = new Scroller(context, MenuDrawer.SMOOTH_INTERPOLATOR);
mPeekScroller = new Scroller(context, DraggableDrawer.PEEK_INTERPOLATOR);
mCloseEnough = dpToPx(DraggableDrawer.CLOSE_ENOUGH);
}
public void toggleMenu(boolean animate) {
if (mDrawerState == STATE_OPEN || mDrawerState == STATE_OPENING) {
closeMenu(animate);
} else if (mDrawerState == STATE_CLOSED || mDrawerState == STATE_CLOSING) {
openMenu(animate);
}
}
public boolean isMenuVisible() {
return mMenuVisible;
}
public void setMenuSize(final int size) {
mMenuSize = size;
if (mDrawerState == STATE_OPEN || mDrawerState == STATE_OPENING) {
setOffsetPixels(mMenuSize);
}
requestLayout();
invalidate();
}
public void setOffsetMenuEnabled(boolean offsetMenu) {
if (offsetMenu != mOffsetMenu) {
mOffsetMenu = offsetMenu;
requestLayout();
invalidate();
}
}
public boolean getOffsetMenuEnabled() {
return mOffsetMenu;
}
public void peekDrawer() {
peekDrawer(DEFAULT_PEEK_START_DELAY, DEFAULT_PEEK_DELAY);
}
public void peekDrawer(long delay) {
peekDrawer(DEFAULT_PEEK_START_DELAY, delay);
}
public void peekDrawer(final long startDelay, final long delay) {
if (startDelay < 0) {
throw new IllegalArgumentException("startDelay must be zero or larger.");
}
if (delay < 0) {
throw new IllegalArgumentException("delay must be zero or larger");
}
removeCallbacks(mPeekRunnable);
removeCallbacks(mPeekStartRunnable);
mPeekDelay = delay;
mPeekStartRunnable = new Runnable() {
@Override
public void run() {
startPeek();
}
};
postDelayed(mPeekStartRunnable, startDelay);
}
public void setHardwareLayerEnabled(boolean enabled) {
if (enabled != mHardwareLayersEnabled) {
mHardwareLayersEnabled = enabled;
mMenuContainer.setHardwareLayersEnabled(enabled);
mContentContainer.setHardwareLayersEnabled(enabled);
stopLayerTranslation();
}
}
public int getTouchMode() {
return mTouchMode;
}
public void setTouchMode(int mode) {
if (mTouchMode != mode) {
mTouchMode = mode;
updateTouchAreaSize();
}
}
public void setTouchBezelSize(int size) {
mTouchBezelSize = size;
}
public int getTouchBezelSize() {
return mTouchBezelSize;
}
/**
* If possible, set the layer type to {@link android.view.View#LAYER_TYPE_HARDWARE}.
*/
protected void startLayerTranslation() {
if (USE_TRANSLATIONS && mHardwareLayersEnabled && !mLayerTypeHardware) {
mLayerTypeHardware = true;
mContentContainer.setLayerType(View.LAYER_TYPE_HARDWARE, null);
mMenuContainer.setLayerType(View.LAYER_TYPE_HARDWARE, null);
}
}
/**
* If the current layer type is {@link android.view.View#LAYER_TYPE_HARDWARE}, this will set it to
* {@link View#LAYER_TYPE_NONE}.
*/
protected void stopLayerTranslation() {
if (mLayerTypeHardware) {
mLayerTypeHardware = false;
mContentContainer.setLayerType(View.LAYER_TYPE_NONE, null);
mMenuContainer.setLayerType(View.LAYER_TYPE_NONE, null);
}
}
/**
* Called when a drag has been ended.
*/
protected void endDrag() {
mIsDragging = false;
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
}
/**
* Stops ongoing animation of the drawer.
*/
protected void stopAnimation() {
removeCallbacks(mDragRunnable);
mScroller.abortAnimation();
stopLayerTranslation();
}
/**
* Called when a drawer animation has successfully completed.
*/
private void completeAnimation() {
mScroller.abortAnimation();
final int finalX = mScroller.getFinalX();
setOffsetPixels(finalX);
setDrawerState(finalX == 0 ? STATE_CLOSED : STATE_OPEN);
stopLayerTranslation();
}
protected void cancelContentTouch() {
final long now = SystemClock.uptimeMillis();
final MotionEvent cancelEvent = MotionEvent.obtain(now, now, MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
getChildAt(i).dispatchTouchEvent(cancelEvent);
}
mContentContainer.dispatchTouchEvent(cancelEvent);
cancelEvent.recycle();
}
/**
* Moves the drawer to the position passed.
*
* @param position The position the content is moved to.
* @param velocity Optional velocity if called by releasing a drag event.
* @param animate Whether the move is animated.
*/
protected void animateOffsetTo(int position, int velocity, boolean animate) {
endDrag();
endPeek();
final int startX = (int) mOffsetPixels;
final int dx = position - startX;
if (dx == 0 || !animate) {
setOffsetPixels(position);
setDrawerState(position == 0 ? STATE_CLOSED : STATE_OPEN);
stopLayerTranslation();
return;
}
int duration;
velocity = Math.abs(velocity);
if (velocity > 0) {
duration = 4 * Math.round(1000.f * Math.abs((float) dx / velocity));
} else {
duration = (int) (600.f * Math.abs((float) dx / mMenuSize));
}
duration = Math.min(duration, mMaxAnimationDuration);
animateOffsetTo(position, duration);
}
protected void animateOffsetTo(int position, int duration) {
final int startX = (int) mOffsetPixels;
final int dx = position - startX;
if (dx > 0) {
setDrawerState(STATE_OPENING);
mScroller.startScroll(startX, 0, dx, 0, duration);
} else {
setDrawerState(STATE_CLOSING);
mScroller.startScroll(startX, 0, dx, 0, duration);
}
startLayerTranslation();
postAnimationInvalidate();
}
/**
* Callback when each frame in the drawer animation should be drawn.
*/
private void postAnimationInvalidate() {
if (mScroller.computeScrollOffset()) {
final int oldX = (int) mOffsetPixels;
final int x = mScroller.getCurrX();
if (x != oldX) setOffsetPixels(x);
if (x != mScroller.getFinalX()) {
postOnAnimation(mDragRunnable);
return;
}
}
completeAnimation();
}
/**
* Starts peek drawer animation.
*/
protected void startPeek() {
initPeekScroller();
startLayerTranslation();
peekDrawerInvalidate();
}
protected abstract void initPeekScroller();
/**
* Callback when each frame in the peek drawer animation should be drawn.
*/
private void peekDrawerInvalidate() {
if (mPeekScroller.computeScrollOffset()) {
final int oldX = (int) mOffsetPixels;
final int x = mPeekScroller.getCurrX();
if (x != oldX) setOffsetPixels(x);
if (!mPeekScroller.isFinished()) {
postOnAnimation(mPeekRunnable);
return;
} else if (mPeekDelay > 0) {
mPeekStartRunnable = new Runnable() {
@Override
public void run() {
startPeek();
}
};
postDelayed(mPeekStartRunnable, mPeekDelay);
}
}
completePeek();
}
/**
* Called when the peek drawer animation has successfully completed.
*/
private void completePeek() {
mPeekScroller.abortAnimation();
setOffsetPixels(0);
setDrawerState(STATE_CLOSED);
stopLayerTranslation();
}
/**
* Stops ongoing peek drawer animation.
*/
protected void endPeek() {
removeCallbacks(mPeekStartRunnable);
removeCallbacks(mPeekRunnable);
stopLayerTranslation();
}
protected boolean isCloseEnough() {
return Math.abs(mOffsetPixels) <= mCloseEnough;
}
protected boolean canChildrenScroll(int dx, int dy, int x, int y) {
boolean canScroll = false;
switch (getPosition()) {
case LEFT:
case RIGHT:
if (!mMenuVisible) {
canScroll = canChildScrollHorizontally(mContentContainer, false, dx,
x - ViewHelper.getLeft(mContentContainer), y - ViewHelper.getTop(mContentContainer));
} else {
canScroll = canChildScrollHorizontally(mMenuContainer, false, dx,
x - ViewHelper.getLeft(mMenuContainer), y - ViewHelper.getTop(mContentContainer));
}
break;
case TOP:
case BOTTOM:
if (!mMenuVisible) {
canScroll = canChildScrollVertically(mContentContainer, false, dy,
x - ViewHelper.getLeft(mContentContainer), y - ViewHelper.getTop(mContentContainer));
} else {
canScroll = canChildScrollVertically(mMenuContainer, false, dy,
x - ViewHelper.getLeft(mMenuContainer), y - ViewHelper.getTop(mContentContainer));
}
}
return canScroll;
}
/**
* Tests scrollability within child views of v given a delta of dx.
*
* @param v View to test for horizontal scrollability
* @param checkV Whether the view should be checked for draggability
* @param dx Delta scrolled in pixels
* @param x X coordinate of the active touch point
* @param y Y coordinate of the active touch point
* @return true if child views of v can be scrolled by delta of dx.
*/
protected boolean canChildScrollHorizontally(View v, boolean checkV, int dx, int x, int y) {
if (v instanceof ViewGroup) {
final ViewGroup group = (ViewGroup) v;
final int count = group.getChildCount();
// Count backwards - let topmost views consume scroll distance first.
for (int i = count - 1; i >= 0; i--) {
final View child = group.getChildAt(i);
final int childLeft = child.getLeft() + supportGetTranslationX(child);
final int childRight = child.getRight() + supportGetTranslationX(child);
final int childTop = child.getTop() + supportGetTranslationY(child);
final int childBottom = child.getBottom() + supportGetTranslationY(child);
if (x >= childLeft && x < childRight && y >= childTop && y < childBottom
&& canChildScrollHorizontally(child, true, dx, x - childLeft, y - childTop)) {
return true;
}
}
}
return checkV && mOnInterceptMoveEventListener.isViewDraggable(v, dx, x, y);
}
/**
* Tests scrollability within child views of v given a delta of dx.
*
* @param v View to test for horizontal scrollability
* @param checkV Whether the view should be checked for draggability
* @param dx Delta scrolled in pixels
* @param x X coordinate of the active touch point
* @param y Y coordinate of the active touch point
* @return true if child views of v can be scrolled by delta of dx.
*/
protected boolean canChildScrollVertically(View v, boolean checkV, int dx, int x, int y) {
if (v instanceof ViewGroup) {
final ViewGroup group = (ViewGroup) v;
final int count = group.getChildCount();
// Count backwards - let topmost views consume scroll distance first.
for (int i = count - 1; i >= 0; i--) {
final View child = group.getChildAt(i);
final int childLeft = child.getLeft() + supportGetTranslationX(child);
final int childRight = child.getRight() + supportGetTranslationX(child);
final int childTop = child.getTop() + supportGetTranslationY(child);
final int childBottom = child.getBottom() + supportGetTranslationY(child);
if (x >= childLeft && x < childRight && y >= childTop && y < childBottom
&& canChildScrollVertically(child, true, dx, x - childLeft, y - childTop)) {
return true;
}
}
}
return checkV && mOnInterceptMoveEventListener.isViewDraggable(v, dx, x, y);
}
protected float getXVelocity(VelocityTracker velocityTracker) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {
return velocityTracker.getXVelocity(mActivePointerId);
}
return velocityTracker.getXVelocity();
}
protected float getYVelocity(VelocityTracker velocityTracker) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {
return velocityTracker.getYVelocity(mActivePointerId);
}
return velocityTracker.getYVelocity();
}
private int supportGetTranslationY(View v) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
return (int) v.getTranslationY();
}
return 0;
}
private int supportGetTranslationX(View v) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
return (int) v.getTranslationX();
}
return 0;
}
void saveState(Bundle state) {
final boolean menuVisible = mDrawerState == STATE_OPEN || mDrawerState == STATE_OPENING;
state.putBoolean(STATE_MENU_VISIBLE, menuVisible);
}
public void restoreState(Parcelable in) {
super.restoreState(in);
Bundle state = (Bundle) in;
final boolean menuOpen = state.getBoolean(STATE_MENU_VISIBLE);
if (menuOpen) {
openMenu(false);
} else {
setOffsetPixels(0);
}
mDrawerState = menuOpen ? STATE_OPEN : STATE_CLOSED;
}
}

View File

@ -1,175 +0,0 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.simonvt.menudrawer;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
/**
* This class encapsulates scrolling. The duration of the scroll
* can be passed in the constructor and specifies the maximum time that
* the scrolling animation should take. Past this time, the scrolling is
* automatically moved to its final stage and computeScrollOffset()
* will always return false to indicate that scrolling is over.
*/
class FloatScroller {
private float mStart;
private float mFinal;
private float mCurr;
private long mStartTime;
private int mDuration;
private float mDurationReciprocal;
private float mDeltaX;
private boolean mFinished;
private Interpolator mInterpolator;
/**
* Create a Scroller with the specified interpolator. If the interpolator is
* null, the default (viscous) interpolator will be used. Specify whether or
* not to support progressive "flywheel" behavior in flinging.
*/
public FloatScroller(Interpolator interpolator) {
mFinished = true;
mInterpolator = interpolator;
}
/**
* Returns whether the scroller has finished scrolling.
*
* @return True if the scroller has finished scrolling, false otherwise.
*/
public final boolean isFinished() {
return mFinished;
}
/**
* Force the finished field to a particular value.
*
* @param finished The new finished value.
*/
public final void forceFinished(boolean finished) {
mFinished = finished;
}
/**
* Returns how long the scroll event will take, in milliseconds.
*
* @return The duration of the scroll in milliseconds.
*/
public final int getDuration() {
return mDuration;
}
/**
* Returns the current offset in the scroll.
*
* @return The new offset as an absolute distance from the origin.
*/
public final float getCurr() {
return mCurr;
}
/**
* Returns the start offset in the scroll.
*
* @return The start offset as an absolute distance from the origin.
*/
public final float getStart() {
return mStart;
}
/**
* Returns where the scroll will end. Valid only for "fling" scrolls.
*
* @return The final offset as an absolute distance from the origin.
*/
public final float getFinal() {
return mFinal;
}
public boolean computeScrollOffset() {
if (mFinished) {
return false;
}
int timePassed = (int) (AnimationUtils.currentAnimationTimeMillis() - mStartTime);
if (timePassed < mDuration) {
float x = timePassed * mDurationReciprocal;
x = mInterpolator.getInterpolation(x);
mCurr = mStart + x * mDeltaX;
} else {
mCurr = mFinal;
mFinished = true;
}
return true;
}
public void startScroll(float start, float delta, int duration) {
mFinished = false;
mDuration = duration;
mStartTime = AnimationUtils.currentAnimationTimeMillis();
mStart = start;
mFinal = start + delta;
mDeltaX = delta;
mDurationReciprocal = 1.0f / (float) mDuration;
}
/**
* Stops the animation. Contrary to {@link #forceFinished(boolean)},
* aborting the animating cause the scroller to move to the final x and y
* position
*
* @see #forceFinished(boolean)
*/
public void abortAnimation() {
mCurr = mFinal;
mFinished = true;
}
/**
* Extend the scroll animation. This allows a running animation to scroll
* further and longer, when used with {@link #setFinal(float)}.
*
* @param extend Additional time to scroll in milliseconds.
* @see #setFinal(float)
*/
public void extendDuration(int extend) {
int passed = timePassed();
mDuration = passed + extend;
mDurationReciprocal = 1.0f / mDuration;
mFinished = false;
}
/**
* Returns the time elapsed since the beginning of the scrolling.
*
* @return The elapsed time in milliseconds.
*/
public int timePassed() {
return (int) (AnimationUtils.currentAnimationTimeMillis() - mStartTime);
}
public void setFinal(float newVal) {
mFinal = newVal;
mDeltaX = mFinal - mStart;
mFinished = false;
}
}

View File

@ -1,28 +0,0 @@
package net.simonvt.menudrawer;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
/**
* FrameLayout which doesn't let touch events propagate to views positioned behind it in the view hierarchy.
*/
class NoClickThroughFrameLayout extends BuildLayerFrameLayout {
public NoClickThroughFrameLayout(Context context) {
super(context);
}
public NoClickThroughFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NoClickThroughFrameLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return true;
}
}

View File

@ -1,778 +0,0 @@
package net.simonvt.menudrawer;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.GradientDrawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
public class OverlayDrawer extends DraggableDrawer {
private int mPeekSize;
private Runnable mRevealRunnable = new Runnable() {
@Override
public void run() {
cancelContentTouch();
int animateTo = 0;
switch (getPosition()) {
case RIGHT:
case BOTTOM:
animateTo = -mPeekSize;
break;
default:
animateTo = mPeekSize;
break;
}
animateOffsetTo(animateTo, 250);
}
};
OverlayDrawer(Activity activity, int dragMode) {
super(activity, dragMode);
}
public OverlayDrawer(Context context) {
super(context);
}
public OverlayDrawer(Context context, AttributeSet attrs) {
super(context, attrs);
}
public OverlayDrawer(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void initDrawer(Context context, AttributeSet attrs, int defStyle) {
super.initDrawer(context, attrs, defStyle);
super.addView(mContentContainer, -1, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
if (USE_TRANSLATIONS) {
mContentContainer.setLayerType(View.LAYER_TYPE_NONE, null);
}
mContentContainer.setHardwareLayersEnabled(false);
super.addView(mMenuContainer, -1, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
mPeekSize = dpToPx(20);
}
@Override
protected void drawOverlay(Canvas canvas) {
final int width = getWidth();
final int height = getHeight();
final int offsetPixels = (int) mOffsetPixels;
final float openRatio = Math.abs(mOffsetPixels) / mMenuSize;
switch (getPosition()) {
case LEFT:
mMenuOverlay.setBounds(offsetPixels, 0, width, height);
break;
case RIGHT:
mMenuOverlay.setBounds(0, 0, width + offsetPixels, height);
break;
case TOP:
mMenuOverlay.setBounds(0, offsetPixels, width, height);
break;
case BOTTOM:
mMenuOverlay.setBounds(0, 0, width, height + offsetPixels);
break;
}
mMenuOverlay.setAlpha((int) (MAX_MENU_OVERLAY_ALPHA * openRatio));
mMenuOverlay.draw(canvas);
}
@Override
public void openMenu(boolean animate) {
int animateTo = 0;
switch (getPosition()) {
case LEFT:
case TOP:
animateTo = mMenuSize;
break;
case RIGHT:
case BOTTOM:
animateTo = -mMenuSize;
break;
}
animateOffsetTo(animateTo, 0, animate);
}
@Override
public void closeMenu(boolean animate) {
animateOffsetTo(0, 0, animate);
}
@Override
protected void onOffsetPixelsChanged(int offsetPixels) {
if (USE_TRANSLATIONS) {
switch (getPosition()) {
case LEFT:
mMenuContainer.setTranslationX(offsetPixels - mMenuSize);
break;
case TOP:
mMenuContainer.setTranslationY(offsetPixels - mMenuSize);
break;
case RIGHT:
mMenuContainer.setTranslationX(offsetPixels + mMenuSize);
break;
case BOTTOM:
mMenuContainer.setTranslationY(offsetPixels + mMenuSize);
break;
}
} else {
switch (getPosition()) {
case TOP:
mMenuContainer.offsetTopAndBottom(offsetPixels - mMenuContainer.getBottom());
break;
case BOTTOM:
mMenuContainer.offsetTopAndBottom(offsetPixels - (mMenuContainer.getTop() - getHeight()));
break;
case LEFT:
mMenuContainer.offsetLeftAndRight(offsetPixels - mMenuContainer.getRight());
break;
case RIGHT:
mMenuContainer.offsetLeftAndRight(offsetPixels - (mMenuContainer.getLeft() - getWidth()));
break;
}
}
invalidate();
}
@Override
protected void initPeekScroller() {
switch (getPosition()) {
case RIGHT:
case BOTTOM: {
final int dx = -mPeekSize;
mPeekScroller.startScroll(0, 0, dx, 0, PEEK_DURATION);
break;
}
default: {
final int dx = mPeekSize;
mPeekScroller.startScroll(0, 0, dx, 0, PEEK_DURATION);
break;
}
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
onOffsetPixelsChanged((int) mOffsetPixels);
}
@Override
protected GradientDrawable.Orientation getDropShadowOrientation() {
switch (getPosition()) {
case TOP:
return GradientDrawable.Orientation.TOP_BOTTOM;
case RIGHT:
return GradientDrawable.Orientation.RIGHT_LEFT;
case BOTTOM:
return GradientDrawable.Orientation.BOTTOM_TOP;
default:
return GradientDrawable.Orientation.LEFT_RIGHT;
}
}
@Override
protected void updateDropShadowRect() {
final float openRatio = Math.abs(mOffsetPixels) / mMenuSize;
final int dropShadowSize = (int) (mDropShadowSize * openRatio);
switch (getPosition()) {
case LEFT:
mDropShadowRect.top = 0;
mDropShadowRect.bottom = getHeight();
mDropShadowRect.left = ViewHelper.getRight(mMenuContainer);
mDropShadowRect.right = mDropShadowRect.left + dropShadowSize;
break;
case TOP:
mDropShadowRect.left = 0;
mDropShadowRect.right = getWidth();
mDropShadowRect.top = ViewHelper.getBottom(mMenuContainer);
mDropShadowRect.bottom = mDropShadowRect.top + dropShadowSize;
break;
case RIGHT:
mDropShadowRect.top = 0;
mDropShadowRect.bottom = getHeight();
mDropShadowRect.right = ViewHelper.getLeft(mMenuContainer);
mDropShadowRect.left = mDropShadowRect.right - dropShadowSize;
break;
case BOTTOM:
mDropShadowRect.left = 0;
mDropShadowRect.right = getWidth();
mDropShadowRect.bottom = ViewHelper.getTop(mMenuContainer);
mDropShadowRect.top = mDropShadowRect.bottom - dropShadowSize;
break;
}
}
@Override
protected void startLayerTranslation() {
if (USE_TRANSLATIONS && mHardwareLayersEnabled && !mLayerTypeHardware) {
mLayerTypeHardware = true;
mMenuContainer.setLayerType(View.LAYER_TYPE_HARDWARE, null);
}
}
@Override
protected void stopLayerTranslation() {
if (mLayerTypeHardware) {
mLayerTypeHardware = false;
mMenuContainer.setLayerType(View.LAYER_TYPE_NONE, null);
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int width = r - l;
final int height = b - t;
mContentContainer.layout(0, 0, width, height);
if (USE_TRANSLATIONS) {
switch (getPosition()) {
case LEFT:
mMenuContainer.layout(0, 0, mMenuSize, height);
break;
case RIGHT:
mMenuContainer.layout(width - mMenuSize, 0, width, height);
break;
case TOP:
mMenuContainer.layout(0, 0, width, mMenuSize);
break;
case BOTTOM:
mMenuContainer.layout(0, height - mMenuSize, width, height);
break;
}
} else {
final int offsetPixels = (int) mOffsetPixels;
final int menuSize = mMenuSize;
switch (getPosition()) {
case LEFT:
mMenuContainer.layout(-menuSize + offsetPixels, 0, offsetPixels, height);
break;
case RIGHT:
mMenuContainer.layout(width + offsetPixels, 0, width + menuSize + offsetPixels, height);
break;
case TOP:
mMenuContainer.layout(0, -menuSize + offsetPixels, width, offsetPixels);
break;
case BOTTOM:
mMenuContainer.layout(0, height + offsetPixels, width, height + menuSize + offsetPixels);
break;
}
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (widthMode == MeasureSpec.UNSPECIFIED || heightMode == MeasureSpec.UNSPECIFIED) {
throw new IllegalStateException("Must measure with an exact size");
}
final int width = MeasureSpec.getSize(widthMeasureSpec);
final int height = MeasureSpec.getSize(heightMeasureSpec);
if (mOffsetPixels == -1) openMenu(false);
int menuWidthMeasureSpec;
int menuHeightMeasureSpec;
switch (getPosition()) {
case TOP:
case BOTTOM:
menuWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, 0, width);
menuHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, 0, mMenuSize);
break;
default:
// LEFT/RIGHT
menuWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, 0, mMenuSize);
menuHeightMeasureSpec = getChildMeasureSpec(widthMeasureSpec, 0, height);
}
mMenuContainer.measure(menuWidthMeasureSpec, menuHeightMeasureSpec);
final int contentWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, 0, width);
final int contentHeightMeasureSpec = getChildMeasureSpec(widthMeasureSpec, 0, height);
mContentContainer.measure(contentWidthMeasureSpec, contentHeightMeasureSpec);
setMeasuredDimension(width, height);
updateTouchAreaSize();
}
private boolean isContentTouch(int x, int y) {
boolean contentTouch = false;
switch (getPosition()) {
case LEFT:
contentTouch = ViewHelper.getRight(mMenuContainer) < x;
break;
case RIGHT:
contentTouch = ViewHelper.getLeft(mMenuContainer) > x;
break;
case TOP:
contentTouch = ViewHelper.getBottom(mMenuContainer) < y;
break;
case BOTTOM:
contentTouch = ViewHelper.getTop(mMenuContainer) > y;
break;
}
return contentTouch;
}
protected boolean onDownAllowDrag(int x, int y) {
switch (getPosition()) {
case LEFT:
return (!mMenuVisible && mInitialMotionX <= mTouchSize)
|| (mMenuVisible && mInitialMotionX <= mOffsetPixels);
case RIGHT:
final int width = getWidth();
final int initialMotionX = (int) mInitialMotionX;
return (!mMenuVisible && initialMotionX >= width - mTouchSize)
|| (mMenuVisible && initialMotionX >= width + mOffsetPixels);
case TOP:
return (!mMenuVisible && mInitialMotionY <= mTouchSize)
|| (mMenuVisible && mInitialMotionY <= mOffsetPixels);
case BOTTOM:
final int height = getHeight();
return (!mMenuVisible && mInitialMotionY >= height - mTouchSize)
|| (mMenuVisible && mInitialMotionY >= height + mOffsetPixels);
}
return false;
}
protected boolean onMoveAllowDrag(int x, int y, float dx, float dy) {
if (mMenuVisible && mTouchMode == TOUCH_MODE_FULLSCREEN) {
return true;
}
switch (getPosition()) {
case LEFT:
return (!mMenuVisible && mInitialMotionX <= mTouchSize && (dx > 0)) // Drawer closed
|| (mMenuVisible && x <= mOffsetPixels) // Drawer open
|| (Math.abs(mOffsetPixels) <= mPeekSize && mMenuVisible); // Drawer revealed
case RIGHT:
final int width = getWidth();
return (!mMenuVisible && mInitialMotionX >= width - mTouchSize && (dx < 0))
|| (mMenuVisible && x >= width - mOffsetPixels)
|| (Math.abs(mOffsetPixels) <= mPeekSize && mMenuVisible);
case TOP:
return (!mMenuVisible && mInitialMotionY <= mTouchSize && (dy > 0))
|| (mMenuVisible && x <= mOffsetPixels)
|| (Math.abs(mOffsetPixels) <= mPeekSize && mMenuVisible);
case BOTTOM:
final int height = getHeight();
return (!mMenuVisible && mInitialMotionY >= height - mTouchSize && (dy < 0))
|| (mMenuVisible && x >= height - mOffsetPixels)
|| (Math.abs(mOffsetPixels) <= mPeekSize && mMenuVisible);
}
return false;
}
protected void onMoveEvent(float dx, float dy) {
switch (getPosition()) {
case LEFT:
setOffsetPixels(Math.min(Math.max(mOffsetPixels + dx, 0), mMenuSize));
break;
case RIGHT:
setOffsetPixels(Math.max(Math.min(mOffsetPixels + dx, 0), -mMenuSize));
break;
case TOP:
setOffsetPixels(Math.min(Math.max(mOffsetPixels + dy, 0), mMenuSize));
break;
case BOTTOM:
setOffsetPixels(Math.max(Math.min(mOffsetPixels + dy, 0), -mMenuSize));
break;
}
}
protected void onUpEvent(int x, int y) {
final int offsetPixels = (int) mOffsetPixels;
switch (getPosition()) {
case LEFT: {
if (mIsDragging) {
mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity);
final int initialVelocity = (int) getXVelocity(mVelocityTracker);
mLastMotionX = x;
animateOffsetTo(initialVelocity > 0 ? mMenuSize : 0, initialVelocity, true);
// Close the menu when content is clicked while the menu is visible.
} else if (mMenuVisible) {
closeMenu();
}
break;
}
case TOP: {
if (mIsDragging) {
mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity);
final int initialVelocity = (int) getYVelocity(mVelocityTracker);
mLastMotionY = y;
animateOffsetTo(initialVelocity > 0 ? mMenuSize : 0, initialVelocity, true);
// Close the menu when content is clicked while the menu is visible.
} else if (mMenuVisible) {
closeMenu();
}
break;
}
case RIGHT: {
final int width = getWidth();
if (mIsDragging) {
mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity);
final int initialVelocity = (int) getXVelocity(mVelocityTracker);
mLastMotionX = x;
animateOffsetTo(initialVelocity > 0 ? 0 : -mMenuSize, initialVelocity, true);
// Close the menu when content is clicked while the menu is visible.
} else if (mMenuVisible) {
closeMenu();
}
break;
}
case BOTTOM: {
if (mIsDragging) {
mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity);
final int initialVelocity = (int) getYVelocity(mVelocityTracker);
mLastMotionY = y;
animateOffsetTo(initialVelocity < 0 ? -mMenuSize : 0, initialVelocity, true);
// Close the menu when content is clicked while the menu is visible.
} else if (mMenuVisible) {
closeMenu();
}
break;
}
}
}
protected boolean checkTouchSlop(float dx, float dy) {
switch (getPosition()) {
case TOP:
case BOTTOM:
return Math.abs(dy) > mTouchSlop && Math.abs(dy) > Math.abs(dx);
default:
return Math.abs(dx) > mTouchSlop && Math.abs(dx) > Math.abs(dy);
}
}
@Override
protected void stopAnimation() {
super.stopAnimation();
removeCallbacks(mRevealRunnable);
}
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = ev.getAction() & MotionEvent.ACTION_MASK;
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
removeCallbacks(mRevealRunnable);
mActivePointerId = INVALID_POINTER;
mIsDragging = false;
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
if (Math.abs(mOffsetPixels) > mMenuSize / 2) {
openMenu();
} else {
closeMenu();
}
return false;
}
if (action == MotionEvent.ACTION_DOWN && mMenuVisible && isCloseEnough()) {
setOffsetPixels(0);
stopAnimation();
endPeek();
setDrawerState(STATE_CLOSED);
mIsDragging = false;
}
// Always intercept events over the content while menu is visible.
if (mMenuVisible) {
int index = 0;
if (mActivePointerId != INVALID_POINTER) {
index = ev.findPointerIndex(mActivePointerId);
index = index == -1 ? 0 : index;
}
final int x = (int) ev.getX(index);
final int y = (int) ev.getY(index);
if (isContentTouch(x, y)) {
return true;
}
}
if (!mMenuVisible && !mIsDragging && mTouchMode == TOUCH_MODE_NONE) {
return false;
}
if (action != MotionEvent.ACTION_DOWN && mIsDragging) {
return true;
}
switch (action) {
case MotionEvent.ACTION_DOWN: {
mLastMotionX = mInitialMotionX = ev.getX();
mLastMotionY = mInitialMotionY = ev.getY();
final boolean allowDrag = onDownAllowDrag((int) mLastMotionX, (int) mLastMotionY);
mActivePointerId = ev.getPointerId(0);
if (allowDrag) {
setDrawerState(mMenuVisible ? STATE_OPEN : STATE_CLOSED);
stopAnimation();
endPeek();
if (!mMenuVisible && mInitialMotionX <= mPeekSize) {
postDelayed(mRevealRunnable, 160);
}
mIsDragging = false;
}
break;
}
case MotionEvent.ACTION_MOVE: {
final int activePointerId = mActivePointerId;
if (activePointerId == INVALID_POINTER) {
// If we don't have a valid id, the touch down wasn't on content.
break;
}
final int pointerIndex = ev.findPointerIndex(activePointerId);
if (pointerIndex == -1) {
mIsDragging = false;
mActivePointerId = INVALID_POINTER;
endDrag();
closeMenu(true);
return false;
}
final float x = ev.getX(pointerIndex);
final float dx = x - mLastMotionX;
final float y = ev.getY(pointerIndex);
final float dy = y - mLastMotionY;
if (Math.abs(dx) >= mTouchSlop || Math.abs(dy) >= mTouchSlop) {
removeCallbacks(mRevealRunnable);
endPeek();
}
if (checkTouchSlop(dx, dy)) {
if (mOnInterceptMoveEventListener != null && (mTouchMode == TOUCH_MODE_FULLSCREEN || mMenuVisible)
&& canChildrenScroll((int) dx, (int) dy, (int) x, (int) y)) {
endDrag(); // Release the velocity tracker
requestDisallowInterceptTouchEvent(true);
return false;
}
final boolean allowDrag = onMoveAllowDrag((int) x, (int) y, dx, dy);
if (allowDrag) {
endPeek();
stopAnimation();
setDrawerState(STATE_DRAGGING);
mIsDragging = true;
mLastMotionX = x;
mLastMotionY = y;
}
}
break;
}
case MotionEvent.ACTION_POINTER_UP:
onPointerUp(ev);
mLastMotionX = ev.getX(ev.findPointerIndex(mActivePointerId));
mLastMotionY = ev.getY(ev.findPointerIndex(mActivePointerId));
break;
}
if (mVelocityTracker == null) mVelocityTracker = VelocityTracker.obtain();
mVelocityTracker.addMovement(ev);
return mIsDragging;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (!mMenuVisible && !mIsDragging && mTouchMode == TOUCH_MODE_NONE) {
return false;
}
final int action = ev.getAction() & MotionEvent.ACTION_MASK;
if (mVelocityTracker == null) mVelocityTracker = VelocityTracker.obtain();
mVelocityTracker.addMovement(ev);
switch (action) {
case MotionEvent.ACTION_DOWN: {
mLastMotionX = mInitialMotionX = ev.getX();
mLastMotionY = mInitialMotionY = ev.getY();
final boolean allowDrag = onDownAllowDrag((int) mLastMotionX, (int) mLastMotionY);
mActivePointerId = ev.getPointerId(0);
if (allowDrag) {
stopAnimation();
endPeek();
if (!mMenuVisible && mLastMotionX <= mPeekSize) {
postDelayed(mRevealRunnable, 160);
}
startLayerTranslation();
}
break;
}
case MotionEvent.ACTION_MOVE: {
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
if (pointerIndex == -1) {
mIsDragging = false;
mActivePointerId = INVALID_POINTER;
endDrag();
closeMenu(true);
return false;
}
if (!mIsDragging) {
final float x = ev.getX(pointerIndex);
final float dx = x - mLastMotionX;
final float y = ev.getY(pointerIndex);
final float dy = y - mLastMotionY;
if (checkTouchSlop(dx, dy)) {
final boolean allowDrag = onMoveAllowDrag((int) x, (int) y, dx, dy);
if (allowDrag) {
endPeek();
stopAnimation();
setDrawerState(STATE_DRAGGING);
mIsDragging = true;
mLastMotionX = x;
mLastMotionY = y;
} else {
mInitialMotionX = x;
mInitialMotionY = y;
}
}
}
if (mIsDragging) {
startLayerTranslation();
final float x = ev.getX(pointerIndex);
final float dx = x - mLastMotionX;
final float y = ev.getY(pointerIndex);
final float dy = y - mLastMotionY;
mLastMotionX = x;
mLastMotionY = y;
onMoveEvent(dx, dy);
}
break;
}
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP: {
removeCallbacks(mRevealRunnable);
int index = ev.findPointerIndex(mActivePointerId);
index = index == -1 ? 0 : index;
final int x = (int) ev.getX(index);
final int y = (int) ev.getY(index);
onUpEvent(x, y);
mActivePointerId = INVALID_POINTER;
mIsDragging = false;
break;
}
case MotionEvent.ACTION_POINTER_DOWN:
final int index = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
>> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
mLastMotionX = ev.getX(index);
mLastMotionY = ev.getY(index);
mActivePointerId = ev.getPointerId(index);
break;
case MotionEvent.ACTION_POINTER_UP:
onPointerUp(ev);
mLastMotionX = ev.getX(ev.findPointerIndex(mActivePointerId));
mLastMotionY = ev.getY(ev.findPointerIndex(mActivePointerId));
break;
}
return true;
}
private void onPointerUp(MotionEvent ev) {
final int pointerIndex = ev.getActionIndex();
final int pointerId = ev.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mLastMotionX = ev.getX(newPointerIndex);
mActivePointerId = ev.getPointerId(newPointerIndex);
if (mVelocityTracker != null) {
mVelocityTracker.clear();
}
}
}
}

View File

@ -1,25 +0,0 @@
package net.simonvt.menudrawer;
import android.view.animation.Interpolator;
class PeekInterpolator implements Interpolator {
private static final SinusoidalInterpolator SINUSOIDAL_INTERPOLATOR = new SinusoidalInterpolator();
@Override
public float getInterpolation(float input) {
float result;
if (input < 1.f / 3.f) {
result = SINUSOIDAL_INTERPOLATOR.getInterpolation(input * 3);
} else if (input > 2.f / 3.f) {
final float val = ((input + 1.f / 3.f) - 1.f) * 3.f;
result = 1.f - SINUSOIDAL_INTERPOLATOR.getInterpolation(val);
} else {
result = 1.f;
}
return result;
}
}

View File

@ -1,50 +0,0 @@
package net.simonvt.menudrawer;
import android.util.SparseArray;
/**
* Enums used for positioning the drawer.
*/
public enum Position {
// Positions the drawer to the left of the content.
LEFT(0),
// Positions the drawer above the content.
TOP(1),
// Positions the drawer to the right of the content.
RIGHT(2),
// Positions the drawer below the content.
BOTTOM(3),
/**
* Position the drawer at the start edge. This will position the drawer to the {@link #LEFT} with LTR languages and
* {@link #RIGHT} with RTL languages.
*/
START(4),
/**
* Position the drawer at the end edge. This will position the drawer to the {@link #RIGHT} with LTR languages and
* {@link #LEFT} with RTL languages.
*/
END(5);
final int mValue;
Position(int value) {
mValue = value;
}
private static final SparseArray<Position> STRING_MAPPING = new SparseArray<Position>();
static {
for (Position via : Position.values()) {
STRING_MAPPING.put(via.mValue, via);
}
}
public static Position fromValue(int value) {
return STRING_MAPPING.get(value);
}
}

View File

@ -1,504 +0,0 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.simonvt.menudrawer;
import android.content.Context;
import android.hardware.SensorManager;
import android.os.Build;
import android.view.ViewConfiguration;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
/**
* This class encapsulates scrolling. The duration of the scroll
* can be passed in the constructor and specifies the maximum time that
* the scrolling animation should take. Past this time, the scrolling is
* automatically moved to its final stage and computeScrollOffset()
* will always return false to indicate that scrolling is over.
*/
class Scroller {
private int mMode;
private int mStartX;
private int mStartY;
private int mFinalX;
private int mFinalY;
private int mMinX;
private int mMaxX;
private int mMinY;
private int mMaxY;
private int mCurrX;
private int mCurrY;
private long mStartTime;
private int mDuration;
private float mDurationReciprocal;
private float mDeltaX;
private float mDeltaY;
private boolean mFinished;
private Interpolator mInterpolator;
private boolean mFlywheel;
private float mVelocity;
private static final int DEFAULT_DURATION = 250;
private static final int SCROLL_MODE = 0;
private static final int FLING_MODE = 1;
private static final float DECELERATION_RATE = (float) (Math.log(0.75) / Math.log(0.9));
private static final float ALPHA = 800; // pixels / seconds
private static final float START_TENSION = 0.4f; // Tension at start: (0.4 * total T, 1.0 * Distance)
private static final float END_TENSION = 1.0f - START_TENSION;
private static final int NB_SAMPLES = 100;
private static final float[] SPLINE = new float[NB_SAMPLES + 1];
private float mDeceleration;
private final float mPpi;
static {
float xMin = 0.0f;
for (int i = 0; i <= NB_SAMPLES; i++) {
final float t = (float) i / NB_SAMPLES;
float xMax = 1.0f;
float x, tx, coef;
while (true) {
x = xMin + (xMax - xMin) / 2.0f;
coef = 3.0f * x * (1.0f - x);
tx = coef * ((1.0f - x) * START_TENSION + x * END_TENSION) + x * x * x;
if (Math.abs(tx - t) < 1E-5) break;
if (tx > t) xMax = x;
else xMin = x;
}
final float d = coef + x * x * x;
SPLINE[i] = d;
}
SPLINE[NB_SAMPLES] = 1.0f;
// This controls the viscous fluid effect (how much of it)
sViscousFluidScale = 8.0f;
// must be set to 1.0 (used in viscousFluid())
sViscousFluidNormalize = 1.0f;
sViscousFluidNormalize = 1.0f / viscousFluid(1.0f);
}
private static float sViscousFluidScale;
private static float sViscousFluidNormalize;
/**
* Create a Scroller with the default duration and interpolator.
*/
public Scroller(Context context) {
this(context, null);
}
/**
* Create a Scroller with the specified interpolator. If the interpolator is
* null, the default (viscous) interpolator will be used. "Flywheel" behavior will
* be in effect for apps targeting Honeycomb or newer.
*/
public Scroller(Context context, Interpolator interpolator) {
this(context, interpolator,
context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB);
}
/**
* Create a Scroller with the specified interpolator. If the interpolator is
* null, the default (viscous) interpolator will be used. Specify whether or
* not to support progressive "flywheel" behavior in flinging.
*/
public Scroller(Context context, Interpolator interpolator, boolean flywheel) {
mFinished = true;
mInterpolator = interpolator;
mPpi = context.getResources().getDisplayMetrics().density * 160.0f;
mDeceleration = computeDeceleration(ViewConfiguration.getScrollFriction());
mFlywheel = flywheel;
}
/**
* The amount of friction applied to flings. The default value
* is {@link android.view.ViewConfiguration#getScrollFriction}.
*
* @param friction A scalar dimension-less value representing the coefficient of
* friction.
*/
public final void setFriction(float friction) {
mDeceleration = computeDeceleration(friction);
}
private float computeDeceleration(float friction) {
return SensorManager.GRAVITY_EARTH // g (m/s^2)
* 39.37f // inch/meter
* mPpi // pixels per inch
* friction;
}
/**
*
* Returns whether the scroller has finished scrolling.
*
* @return True if the scroller has finished scrolling, false otherwise.
*/
public final boolean isFinished() {
return mFinished;
}
/**
* Force the finished field to a particular value.
*
* @param finished The new finished value.
*/
public final void forceFinished(boolean finished) {
mFinished = finished;
}
/**
* Returns how long the scroll event will take, in milliseconds.
*
* @return The duration of the scroll in milliseconds.
*/
public final int getDuration() {
return mDuration;
}
/**
* Returns the current X offset in the scroll.
*
* @return The new X offset as an absolute distance from the origin.
*/
public final int getCurrX() {
return mCurrX;
}
/**
* Returns the current Y offset in the scroll.
*
* @return The new Y offset as an absolute distance from the origin.
*/
public final int getCurrY() {
return mCurrY;
}
/**
* Returns the current velocity.
*
* @return The original velocity less the deceleration. Result may be
* negative.
*/
public float getCurrVelocity() {
return mVelocity - mDeceleration * timePassed() / 2000.0f;
}
/**
* Returns the start X offset in the scroll.
*
* @return The start X offset as an absolute distance from the origin.
*/
public final int getStartX() {
return mStartX;
}
/**
* Returns the start Y offset in the scroll.
*
* @return The start Y offset as an absolute distance from the origin.
*/
public final int getStartY() {
return mStartY;
}
/**
* Returns where the scroll will end. Valid only for "fling" scrolls.
*
* @return The final X offset as an absolute distance from the origin.
*/
public final int getFinalX() {
return mFinalX;
}
/**
* Returns where the scroll will end. Valid only for "fling" scrolls.
*
* @return The final Y offset as an absolute distance from the origin.
*/
public final int getFinalY() {
return mFinalY;
}
/**
* Call this when you want to know the new location. If it returns true,
* the animation is not yet finished. loc will be altered to provide the
* new location.
*/
public boolean computeScrollOffset() {
if (mFinished) {
return false;
}
int timePassed = (int) (AnimationUtils.currentAnimationTimeMillis() - mStartTime);
if (timePassed < mDuration) {
switch (mMode) {
case SCROLL_MODE:
float x = timePassed * mDurationReciprocal;
if (mInterpolator == null)
x = viscousFluid(x);
else
x = mInterpolator.getInterpolation(x);
mCurrX = mStartX + Math.round(x * mDeltaX);
mCurrY = mStartY + Math.round(x * mDeltaY);
break;
case FLING_MODE:
final float t = (float) timePassed / mDuration;
final int index = (int) (NB_SAMPLES * t);
final float tInf = (float) index / NB_SAMPLES;
final float tSup = (float) (index + 1) / NB_SAMPLES;
final float dInf = SPLINE[index];
final float dSup = SPLINE[index + 1];
final float distanceCoef = dInf + (t - tInf) / (tSup - tInf) * (dSup - dInf);
mCurrX = mStartX + Math.round(distanceCoef * (mFinalX - mStartX));
// Pin to mMinX <= mCurrX <= mMaxX
mCurrX = Math.min(mCurrX, mMaxX);
mCurrX = Math.max(mCurrX, mMinX);
mCurrY = mStartY + Math.round(distanceCoef * (mFinalY - mStartY));
// Pin to mMinY <= mCurrY <= mMaxY
mCurrY = Math.min(mCurrY, mMaxY);
mCurrY = Math.max(mCurrY, mMinY);
if (mCurrX == mFinalX && mCurrY == mFinalY) {
mFinished = true;
}
break;
}
} else {
mCurrX = mFinalX;
mCurrY = mFinalY;
mFinished = true;
}
return true;
}
/**
* Start scrolling by providing a starting point and the distance to travel.
* The scroll will use the default value of 250 milliseconds for the
* duration.
*
* @param startX Starting horizontal scroll offset in pixels. Positive
* numbers will scroll the content to the left.
* @param startY Starting vertical scroll offset in pixels. Positive numbers
* will scroll the content up.
* @param dx Horizontal distance to travel. Positive numbers will scroll the
* content to the left.
* @param dy Vertical distance to travel. Positive numbers will scroll the
* content up.
*/
public void startScroll(int startX, int startY, int dx, int dy) {
startScroll(startX, startY, dx, dy, DEFAULT_DURATION);
}
/**
* Start scrolling by providing a starting point and the distance to travel.
*
* @param startX Starting horizontal scroll offset in pixels. Positive
* numbers will scroll the content to the left.
* @param startY Starting vertical scroll offset in pixels. Positive numbers
* will scroll the content up.
* @param dx Horizontal distance to travel. Positive numbers will scroll the
* content to the left.
* @param dy Vertical distance to travel. Positive numbers will scroll the
* content up.
* @param duration Duration of the scroll in milliseconds.
*/
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
mMode = SCROLL_MODE;
mFinished = false;
mDuration = duration;
mStartTime = AnimationUtils.currentAnimationTimeMillis();
mStartX = startX;
mStartY = startY;
mFinalX = startX + dx;
mFinalY = startY + dy;
mDeltaX = dx;
mDeltaY = dy;
mDurationReciprocal = 1.0f / (float) mDuration;
}
/**
* Start scrolling based on a fling gesture. The distance travelled will
* depend on the initial velocity of the fling.
*
* @param startX Starting point of the scroll (X)
* @param startY Starting point of the scroll (Y)
* @param velocityX Initial velocity of the fling (X) measured in pixels per
* second.
* @param velocityY Initial velocity of the fling (Y) measured in pixels per
* second
* @param minX Minimum X value. The scroller will not scroll past this
* point.
* @param maxX Maximum X value. The scroller will not scroll past this
* point.
* @param minY Minimum Y value. The scroller will not scroll past this
* point.
* @param maxY Maximum Y value. The scroller will not scroll past this
* point.
*/
public void fling(int startX, int startY, int velocityX, int velocityY,
int minX, int maxX, int minY, int maxY) {
// Continue a scroll or fling in progress
if (mFlywheel && !mFinished) {
float oldVel = getCurrVelocity();
float dx = (float) (mFinalX - mStartX);
float dy = (float) (mFinalY - mStartY);
float hyp = (float) Math.sqrt(dx * dx + dy * dy);
float ndx = dx / hyp;
float ndy = dy / hyp;
float oldVelocityX = ndx * oldVel;
float oldVelocityY = ndy * oldVel;
if (Math.signum(velocityX) == Math.signum(oldVelocityX)
&& Math.signum(velocityY) == Math.signum(oldVelocityY)) {
velocityX += oldVelocityX;
velocityY += oldVelocityY;
}
}
mMode = FLING_MODE;
mFinished = false;
float velocity = (float) Math.sqrt(velocityX * velocityX + velocityY * velocityY);
mVelocity = velocity;
final double l = Math.log(START_TENSION * velocity / ALPHA);
mDuration = (int) (1000.0 * Math.exp(l / (DECELERATION_RATE - 1.0)));
mStartTime = AnimationUtils.currentAnimationTimeMillis();
mStartX = startX;
mStartY = startY;
float coeffX = velocity == 0 ? 1.0f : velocityX / velocity;
float coeffY = velocity == 0 ? 1.0f : velocityY / velocity;
int totalDistance =
(int) (ALPHA * Math.exp(DECELERATION_RATE / (DECELERATION_RATE - 1.0) * l));
mMinX = minX;
mMaxX = maxX;
mMinY = minY;
mMaxY = maxY;
mFinalX = startX + Math.round(totalDistance * coeffX);
// Pin to mMinX <= mFinalX <= mMaxX
mFinalX = Math.min(mFinalX, mMaxX);
mFinalX = Math.max(mFinalX, mMinX);
mFinalY = startY + Math.round(totalDistance * coeffY);
// Pin to mMinY <= mFinalY <= mMaxY
mFinalY = Math.min(mFinalY, mMaxY);
mFinalY = Math.max(mFinalY, mMinY);
}
static float viscousFluid(float x) {
x *= sViscousFluidScale;
if (x < 1.0f) {
x -= (1.0f - (float) Math.exp(-x));
} else {
float start = 0.36787944117f; // 1/e == exp(-1)
x = 1.0f - (float) Math.exp(1.0f - x);
x = start + x * (1.0f - start);
}
x *= sViscousFluidNormalize;
return x;
}
/**
* Stops the animation. Contrary to {@link #forceFinished(boolean)},
* aborting the animating cause the scroller to move to the final x and y
* position
*
* @see #forceFinished(boolean)
*/
public void abortAnimation() {
mCurrX = mFinalX;
mCurrY = mFinalY;
mFinished = true;
}
/**
* Extend the scroll animation. This allows a running animation to scroll
* further and longer, when used with {@link #setFinalX(int)} or {@link #setFinalY(int)}.
*
* @param extend Additional time to scroll in milliseconds.
* @see #setFinalX(int)
* @see #setFinalY(int)
*/
public void extendDuration(int extend) {
int passed = timePassed();
mDuration = passed + extend;
mDurationReciprocal = 1.0f / mDuration;
mFinished = false;
}
/**
* Returns the time elapsed since the beginning of the scrolling.
*
* @return The elapsed time in milliseconds.
*/
public int timePassed() {
return (int) (AnimationUtils.currentAnimationTimeMillis() - mStartTime);
}
/**
* Sets the final position (X) for this scroller.
*
* @param newX The new X offset as an absolute distance from the origin.
* @see #extendDuration(int)
* @see #setFinalY(int)
*/
public void setFinalX(int newX) {
mFinalX = newX;
mDeltaX = mFinalX - mStartX;
mFinished = false;
}
/**
* Sets the final position (Y) for this scroller.
*
* @param newY The new Y offset as an absolute distance from the origin.
* @see #extendDuration(int)
* @see #setFinalX(int)
*/
public void setFinalY(int newY) {
mFinalY = newY;
mDeltaY = mFinalY - mStartY;
mFinished = false;
}
/**
* @hide
*/
public boolean isScrollingInDirection(float xvel, float yvel) {
return !mFinished && Math.signum(xvel) == Math.signum(mFinalX - mStartX)
&& Math.signum(yvel) == Math.signum(mFinalY - mStartY);
}
}

View File

@ -1,15 +0,0 @@
package net.simonvt.menudrawer;
import android.view.animation.Interpolator;
/**
* Interpolator which, when drawn from 0 to 1, looks like half a sine-wave. Used for smoother opening/closing when
* peeking at the drawer.
*/
class SinusoidalInterpolator implements Interpolator {
@Override
public float getInterpolation(float input) {
return (float) (0.5f + 0.5f * Math.sin(input * Math.PI - Math.PI / 2.f));
}
}

View File

@ -1,187 +0,0 @@
package net.simonvt.menudrawer;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.drawable.Drawable;
public class SlideDrawable extends Drawable implements Drawable.Callback {
private Drawable mWrapped;
private float mOffset;
private final Rect mTmpRect = new Rect();
private boolean mIsRtl;
public SlideDrawable(Drawable wrapped) {
mWrapped = wrapped;
}
public void setOffset(float offset) {
mOffset = offset;
invalidateSelf();
}
public float getOffset() {
return mOffset;
}
void setIsRtl(boolean isRtl) {
mIsRtl = isRtl;
invalidateSelf();
}
@Override
public void draw(Canvas canvas) {
mWrapped.copyBounds(mTmpRect);
canvas.save();
if (mIsRtl) {
canvas.translate(1.f / 3 * mTmpRect.width() * mOffset, 0);
} else {
canvas.translate(1.f / 3 * mTmpRect.width() * -mOffset, 0);
}
mWrapped.draw(canvas);
canvas.restore();
}
@Override
public void setChangingConfigurations(int configs) {
mWrapped.setChangingConfigurations(configs);
}
@Override
public int getChangingConfigurations() {
return mWrapped.getChangingConfigurations();
}
@Override
public void setDither(boolean dither) {
mWrapped.setDither(dither);
}
@Override
public void setFilterBitmap(boolean filter) {
mWrapped.setFilterBitmap(filter);
}
@Override
public void setAlpha(int alpha) {
mWrapped.setAlpha(alpha);
}
@Override
public void setColorFilter(ColorFilter cf) {
mWrapped.setColorFilter(cf);
}
@Override
public void setColorFilter(int color, PorterDuff.Mode mode) {
mWrapped.setColorFilter(color, mode);
}
@Override
public void clearColorFilter() {
mWrapped.clearColorFilter();
}
@Override
public boolean isStateful() {
return mWrapped.isStateful();
}
@Override
public boolean setState(int[] stateSet) {
return mWrapped.setState(stateSet);
}
@Override
public int[] getState() {
return mWrapped.getState();
}
@Override
public Drawable getCurrent() {
return mWrapped.getCurrent();
}
@Override
public boolean setVisible(boolean visible, boolean restart) {
return super.setVisible(visible, restart);
}
@Override
public int getOpacity() {
return mWrapped.getOpacity();
}
@Override
public Region getTransparentRegion() {
return mWrapped.getTransparentRegion();
}
@Override
protected boolean onStateChange(int[] state) {
mWrapped.setState(state);
return super.onStateChange(state);
}
@Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
mWrapped.setBounds(bounds);
}
@Override
public int getIntrinsicWidth() {
return mWrapped.getIntrinsicWidth();
}
@Override
public int getIntrinsicHeight() {
return mWrapped.getIntrinsicHeight();
}
@Override
public int getMinimumWidth() {
return mWrapped.getMinimumWidth();
}
@Override
public int getMinimumHeight() {
return mWrapped.getMinimumHeight();
}
@Override
public boolean getPadding(Rect padding) {
return mWrapped.getPadding(padding);
}
@Override
public ConstantState getConstantState() {
return super.getConstantState();
}
@Override
public void invalidateDrawable(Drawable who) {
if (who == mWrapped) {
invalidateSelf();
}
}
@Override
public void scheduleDrawable(Drawable who, Runnable what, long when) {
if (who == mWrapped) {
scheduleSelf(what, when);
}
}
@Override
public void unscheduleDrawable(Drawable who, Runnable what) {
if (who == mWrapped) {
unscheduleSelf(what);
}
}
}

View File

@ -1,704 +0,0 @@
package net.simonvt.menudrawer;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
public class SlidingDrawer extends DraggableDrawer {
SlidingDrawer(Activity activity, int dragMode) {
super(activity, dragMode);
}
public SlidingDrawer(Context context) {
super(context);
}
public SlidingDrawer(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SlidingDrawer(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void initDrawer(Context context, AttributeSet attrs, int defStyle) {
super.initDrawer(context, attrs, defStyle);
super.addView(mMenuContainer, -1, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
super.addView(mContentContainer, -1, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
}
@Override
public void openMenu(boolean animate) {
int animateTo = 0;
switch (getPosition()) {
case LEFT:
case TOP:
animateTo = mMenuSize;
break;
case RIGHT:
case BOTTOM:
animateTo = -mMenuSize;
break;
}
animateOffsetTo(animateTo, 0, animate);
}
@Override
public void closeMenu(boolean animate) {
animateOffsetTo(0, 0, animate);
}
@Override
protected void onOffsetPixelsChanged(int offsetPixels) {
if (USE_TRANSLATIONS) {
switch (getPosition()) {
case TOP:
case BOTTOM:
mContentContainer.setTranslationY(offsetPixels);
break;
default:
mContentContainer.setTranslationX(offsetPixels);
break;
}
} else {
switch (getPosition()) {
case TOP:
case BOTTOM:
mContentContainer.offsetTopAndBottom(offsetPixels - mContentContainer.getTop());
break;
default:
mContentContainer.offsetLeftAndRight(offsetPixels - mContentContainer.getLeft());
break;
}
}
offsetMenu(offsetPixels);
invalidate();
}
@Override
protected void initPeekScroller() {
switch (getPosition()) {
case RIGHT:
case BOTTOM: {
final int dx = -mMenuSize / 3;
mPeekScroller.startScroll(0, 0, dx, 0, PEEK_DURATION);
break;
}
default: {
final int dx = mMenuSize / 3;
mPeekScroller.startScroll(0, 0, dx, 0, PEEK_DURATION);
break;
}
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
onOffsetPixelsChanged((int) mOffsetPixels);
}
@Override
protected void drawOverlay(Canvas canvas) {
final int width = getWidth();
final int height = getHeight();
final int offsetPixels = (int) mOffsetPixels;
final float openRatio = Math.abs(mOffsetPixels) / mMenuSize;
switch (getPosition()) {
case LEFT:
mMenuOverlay.setBounds(0, 0, offsetPixels, height);
break;
case RIGHT:
mMenuOverlay.setBounds(width + offsetPixels, 0, width, height);
break;
case TOP:
mMenuOverlay.setBounds(0, 0, width, offsetPixels);
break;
case BOTTOM:
mMenuOverlay.setBounds(0, height + offsetPixels, width, height);
break;
}
mMenuOverlay.setAlpha((int) (MAX_MENU_OVERLAY_ALPHA * (1.f - openRatio)));
mMenuOverlay.draw(canvas);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int width = r - l;
final int height = b - t;
if (USE_TRANSLATIONS) {
mContentContainer.layout(0, 0, width, height);
} else {
final int offsetPixels = (int) mOffsetPixels;
if (getPosition() == Position.LEFT || getPosition() == Position.RIGHT) {
mContentContainer.layout(offsetPixels, 0, width + offsetPixels, height);
} else {
mContentContainer.layout(0, offsetPixels, width, height + offsetPixels);
}
}
switch (getPosition()) {
case LEFT:
mMenuContainer.layout(0, 0, mMenuSize, height);
break;
case RIGHT:
mMenuContainer.layout(width - mMenuSize, 0, width, height);
break;
case TOP:
mMenuContainer.layout(0, 0, width, mMenuSize);
break;
case BOTTOM:
mMenuContainer.layout(0, height - mMenuSize, width, height);
break;
}
}
/**
* Offsets the menu relative to its original position based on the position of the content.
*
* @param offsetPixels The number of pixels the content if offset.
*/
private void offsetMenu(int offsetPixels) {
if (!mOffsetMenu || mMenuSize == 0) {
return;
}
final int width = getWidth();
final int height = getHeight();
final int menuSize = mMenuSize;
final int sign = (int) (mOffsetPixels / Math.abs(mOffsetPixels));
final float openRatio = Math.abs(mOffsetPixels) / menuSize;
final int offset = (int) (-0.25f * ((1.0f - openRatio) * menuSize) * sign);
switch (getPosition()) {
case LEFT: {
if (USE_TRANSLATIONS) {
if (offsetPixels > 0) {
mMenuContainer.setTranslationX(offset);
} else {
mMenuContainer.setTranslationX(-menuSize);
}
} else {
mMenuContainer.offsetLeftAndRight(offset - mMenuContainer.getLeft());
mMenuContainer.setVisibility(offsetPixels == 0 ? INVISIBLE : VISIBLE);
}
break;
}
case RIGHT: {
if (USE_TRANSLATIONS) {
if (offsetPixels != 0) {
mMenuContainer.setTranslationX(offset);
} else {
mMenuContainer.setTranslationX(menuSize);
}
} else {
final int oldOffset = mMenuContainer.getRight() - width;
final int offsetBy = offset - oldOffset;
mMenuContainer.offsetLeftAndRight(offsetBy);
mMenuContainer.setVisibility(offsetPixels == 0 ? INVISIBLE : VISIBLE);
}
break;
}
case TOP: {
if (USE_TRANSLATIONS) {
if (offsetPixels > 0) {
mMenuContainer.setTranslationY(offset);
} else {
mMenuContainer.setTranslationY(-menuSize);
}
} else {
mMenuContainer.offsetTopAndBottom(offset - mMenuContainer.getTop());
mMenuContainer.setVisibility(offsetPixels == 0 ? INVISIBLE : VISIBLE);
}
break;
}
case BOTTOM: {
if (USE_TRANSLATIONS) {
if (offsetPixels != 0) {
mMenuContainer.setTranslationY(offset);
} else {
mMenuContainer.setTranslationY(menuSize);
}
} else {
final int oldOffset = mMenuContainer.getBottom() - height;
final int offsetBy = offset - oldOffset;
mMenuContainer.offsetTopAndBottom(offsetBy);
mMenuContainer.setVisibility(offsetPixels == 0 ? INVISIBLE : VISIBLE);
}
break;
}
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (widthMode == MeasureSpec.UNSPECIFIED || heightMode == MeasureSpec.UNSPECIFIED) {
throw new IllegalStateException("Must measure with an exact size");
}
final int width = MeasureSpec.getSize(widthMeasureSpec);
final int height = MeasureSpec.getSize(heightMeasureSpec);
if (mOffsetPixels == -1) openMenu(false);
int menuWidthMeasureSpec;
int menuHeightMeasureSpec;
switch (getPosition()) {
case TOP:
case BOTTOM:
menuWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, 0, width);
menuHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, 0, mMenuSize);
break;
default:
// LEFT/RIGHT
menuWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, 0, mMenuSize);
menuHeightMeasureSpec = getChildMeasureSpec(widthMeasureSpec, 0, height);
}
mMenuContainer.measure(menuWidthMeasureSpec, menuHeightMeasureSpec);
final int contentWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, 0, width);
final int contentHeightMeasureSpec = getChildMeasureSpec(widthMeasureSpec, 0, height);
mContentContainer.measure(contentWidthMeasureSpec, contentHeightMeasureSpec);
setMeasuredDimension(width, height);
updateTouchAreaSize();
}
private boolean isContentTouch(int x, int y) {
boolean contentTouch = false;
switch (getPosition()) {
case LEFT:
contentTouch = ViewHelper.getLeft(mContentContainer) < x;
break;
case RIGHT:
contentTouch = ViewHelper.getRight(mContentContainer) > x;
break;
case TOP:
contentTouch = ViewHelper.getTop(mContentContainer) < y;
break;
case BOTTOM:
contentTouch = ViewHelper.getBottom(mContentContainer) > y;
break;
}
return contentTouch;
}
protected boolean onDownAllowDrag(int x, int y) {
switch (getPosition()) {
case LEFT:
return (!mMenuVisible && mInitialMotionX <= mTouchSize)
|| (mMenuVisible && mInitialMotionX >= mOffsetPixels);
case RIGHT:
final int width = getWidth();
final int initialMotionX = (int) mInitialMotionX;
return (!mMenuVisible && initialMotionX >= width - mTouchSize)
|| (mMenuVisible && initialMotionX <= width + mOffsetPixels);
case TOP:
return (!mMenuVisible && mInitialMotionY <= mTouchSize)
|| (mMenuVisible && mInitialMotionY >= mOffsetPixels);
case BOTTOM:
final int height = getHeight();
return (!mMenuVisible && mInitialMotionY >= height - mTouchSize)
|| (mMenuVisible && mInitialMotionY <= height + mOffsetPixels);
}
return false;
}
protected boolean onMoveAllowDrag(int x, int y, float dx, float dy) {
switch (getPosition()) {
case LEFT:
return (!mMenuVisible && mInitialMotionX <= mTouchSize && (dx > 0))
|| (mMenuVisible && x >= mOffsetPixels);
case RIGHT:
final int width = getWidth();
return (!mMenuVisible && mInitialMotionX >= width - mTouchSize && (dx < 0))
|| (mMenuVisible && x <= width + mOffsetPixels);
case TOP:
return (!mMenuVisible && mInitialMotionY <= mTouchSize && (dy > 0))
|| (mMenuVisible && y >= mOffsetPixels);
case BOTTOM:
final int height = getHeight();
return (!mMenuVisible && mInitialMotionY >= height - mTouchSize && (dy < 0))
|| (mMenuVisible && y <= height + mOffsetPixels);
}
return false;
}
protected void onMoveEvent(float dx, float dy) {
switch (getPosition()) {
case LEFT:
setOffsetPixels(Math.min(Math.max(mOffsetPixels + dx, 0), mMenuSize));
break;
case RIGHT:
setOffsetPixels(Math.max(Math.min(mOffsetPixels + dx, 0), -mMenuSize));
break;
case TOP:
setOffsetPixels(Math.min(Math.max(mOffsetPixels + dy, 0), mMenuSize));
break;
case BOTTOM:
setOffsetPixels(Math.max(Math.min(mOffsetPixels + dy, 0), -mMenuSize));
break;
}
}
protected void onUpEvent(int x, int y) {
final int offsetPixels = (int) mOffsetPixels;
switch (getPosition()) {
case LEFT: {
if (mIsDragging) {
mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity);
final int initialVelocity = (int) getXVelocity(mVelocityTracker);
mLastMotionX = x;
animateOffsetTo(initialVelocity > 0 ? mMenuSize : 0, initialVelocity, true);
// Close the menu when content is clicked while the menu is visible.
} else if (mMenuVisible && x > offsetPixels) {
closeMenu();
}
break;
}
case TOP: {
if (mIsDragging) {
mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity);
final int initialVelocity = (int) getYVelocity(mVelocityTracker);
mLastMotionY = y;
animateOffsetTo(initialVelocity > 0 ? mMenuSize : 0, initialVelocity, true);
// Close the menu when content is clicked while the menu is visible.
} else if (mMenuVisible && y > offsetPixels) {
closeMenu();
}
break;
}
case RIGHT: {
final int width = getWidth();
if (mIsDragging) {
mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity);
final int initialVelocity = (int) getXVelocity(mVelocityTracker);
mLastMotionX = x;
animateOffsetTo(initialVelocity > 0 ? 0 : -mMenuSize, initialVelocity, true);
// Close the menu when content is clicked while the menu is visible.
} else if (mMenuVisible && x < width + offsetPixels) {
closeMenu();
}
break;
}
case BOTTOM: {
if (mIsDragging) {
mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity);
final int initialVelocity = (int) getYVelocity(mVelocityTracker);
mLastMotionY = y;
animateOffsetTo(initialVelocity < 0 ? -mMenuSize : 0, initialVelocity, true);
// Close the menu when content is clicked while the menu is visible.
} else if (mMenuVisible && y < getHeight() + offsetPixels) {
closeMenu();
}
break;
}
}
}
protected boolean checkTouchSlop(float dx, float dy) {
switch (getPosition()) {
case TOP:
case BOTTOM:
return Math.abs(dy) > mTouchSlop && Math.abs(dy) > Math.abs(dx);
default:
return Math.abs(dx) > mTouchSlop && Math.abs(dx) > Math.abs(dy);
}
}
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = ev.getAction() & MotionEvent.ACTION_MASK;
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
mActivePointerId = INVALID_POINTER;
mIsDragging = false;
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
if (Math.abs(mOffsetPixels) > mMenuSize / 2) {
openMenu();
} else {
closeMenu();
}
return false;
}
if (action == MotionEvent.ACTION_DOWN && mMenuVisible && isCloseEnough()) {
setOffsetPixels(0);
stopAnimation();
endPeek();
setDrawerState(STATE_CLOSED);
mIsDragging = false;
}
// Always intercept events over the content while menu is visible.
if (mMenuVisible) {
int index = 0;
if (mActivePointerId != INVALID_POINTER) {
index = ev.findPointerIndex(mActivePointerId);
index = index == -1 ? 0 : index;
}
final int x = (int) ev.getX(index);
final int y = (int) ev.getY(index);
if (isContentTouch(x, y)) {
return true;
}
}
if (!mMenuVisible && !mIsDragging && mTouchMode == TOUCH_MODE_NONE) {
return false;
}
if (action != MotionEvent.ACTION_DOWN && mIsDragging) {
return true;
}
switch (action) {
case MotionEvent.ACTION_DOWN: {
mLastMotionX = mInitialMotionX = ev.getX();
mLastMotionY = mInitialMotionY = ev.getY();
final boolean allowDrag = onDownAllowDrag((int) mLastMotionX, (int) mLastMotionY);
mActivePointerId = ev.getPointerId(0);
if (allowDrag) {
setDrawerState(mMenuVisible ? STATE_OPEN : STATE_CLOSED);
stopAnimation();
endPeek();
mIsDragging = false;
}
break;
}
case MotionEvent.ACTION_MOVE: {
final int activePointerId = mActivePointerId;
if (activePointerId == INVALID_POINTER) {
// If we don't have a valid id, the touch down wasn't on content.
break;
}
final int pointerIndex = ev.findPointerIndex(activePointerId);
if (pointerIndex == -1) {
mIsDragging = false;
mActivePointerId = INVALID_POINTER;
endDrag();
closeMenu(true);
return false;
}
final float x = ev.getX(pointerIndex);
final float dx = x - mLastMotionX;
final float y = ev.getY(pointerIndex);
final float dy = y - mLastMotionY;
if (checkTouchSlop(dx, dy)) {
if (mOnInterceptMoveEventListener != null && (mTouchMode == TOUCH_MODE_FULLSCREEN || mMenuVisible)
&& canChildrenScroll((int) dx, (int) dy, (int) x, (int) y)) {
endDrag(); // Release the velocity tracker
requestDisallowInterceptTouchEvent(true);
return false;
}
final boolean allowDrag = onMoveAllowDrag((int) x, (int) y, dx, dy);
if (allowDrag) {
setDrawerState(STATE_DRAGGING);
mIsDragging = true;
mLastMotionX = x;
mLastMotionY = y;
}
}
break;
}
case MotionEvent.ACTION_POINTER_UP:
onPointerUp(ev);
mLastMotionX = ev.getX(ev.findPointerIndex(mActivePointerId));
mLastMotionY = ev.getY(ev.findPointerIndex(mActivePointerId));
break;
}
if (mVelocityTracker == null) mVelocityTracker = VelocityTracker.obtain();
mVelocityTracker.addMovement(ev);
return mIsDragging;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (!mMenuVisible && !mIsDragging && mTouchMode == TOUCH_MODE_NONE) {
return false;
}
final int action = ev.getAction() & MotionEvent.ACTION_MASK;
if (mVelocityTracker == null) mVelocityTracker = VelocityTracker.obtain();
mVelocityTracker.addMovement(ev);
switch (action) {
case MotionEvent.ACTION_DOWN: {
mLastMotionX = mInitialMotionX = ev.getX();
mLastMotionY = mInitialMotionY = ev.getY();
final boolean allowDrag = onDownAllowDrag((int) mLastMotionX, (int) mLastMotionY);
mActivePointerId = ev.getPointerId(0);
if (allowDrag) {
stopAnimation();
endPeek();
startLayerTranslation();
}
break;
}
case MotionEvent.ACTION_MOVE: {
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
if (pointerIndex == -1) {
mIsDragging = false;
mActivePointerId = INVALID_POINTER;
endDrag();
closeMenu(true);
return false;
}
if (!mIsDragging) {
final float x = ev.getX(pointerIndex);
final float dx = x - mLastMotionX;
final float y = ev.getY(pointerIndex);
final float dy = y - mLastMotionY;
if (checkTouchSlop(dx, dy)) {
final boolean allowDrag = onMoveAllowDrag((int) x, (int) y, dx, dy);
if (allowDrag) {
setDrawerState(STATE_DRAGGING);
mIsDragging = true;
mLastMotionX = x;
mLastMotionY = y;
} else {
mInitialMotionX = x;
mInitialMotionY = y;
}
}
}
if (mIsDragging) {
startLayerTranslation();
final float x = ev.getX(pointerIndex);
final float dx = x - mLastMotionX;
final float y = ev.getY(pointerIndex);
final float dy = y - mLastMotionY;
mLastMotionX = x;
mLastMotionY = y;
onMoveEvent(dx, dy);
}
break;
}
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP: {
int index = ev.findPointerIndex(mActivePointerId);
index = index == -1 ? 0 : index;
final int x = (int) ev.getX(index);
final int y = (int) ev.getY(index);
onUpEvent(x, y);
mActivePointerId = INVALID_POINTER;
mIsDragging = false;
break;
}
case MotionEvent.ACTION_POINTER_DOWN:
final int index = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
>> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
mLastMotionX = ev.getX(index);
mLastMotionY = ev.getY(index);
mActivePointerId = ev.getPointerId(index);
break;
case MotionEvent.ACTION_POINTER_UP:
onPointerUp(ev);
mLastMotionX = ev.getX(ev.findPointerIndex(mActivePointerId));
mLastMotionY = ev.getY(ev.findPointerIndex(mActivePointerId));
break;
}
return true;
}
private void onPointerUp(MotionEvent ev) {
final int pointerIndex = ev.getActionIndex();
final int pointerId = ev.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mLastMotionX = ev.getX(newPointerIndex);
mActivePointerId = ev.getPointerId(newPointerIndex);
if (mVelocityTracker != null) {
mVelocityTracker.clear();
}
}
}
}

View File

@ -1,12 +0,0 @@
package net.simonvt.menudrawer;
import android.view.animation.Interpolator;
class SmoothInterpolator implements Interpolator {
@Override
public float getInterpolation(float t) {
t -= 1.0f;
return t * t * t * t * t + 1.0f;
}
}

View File

@ -1,218 +0,0 @@
package net.simonvt.menudrawer;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
public class StaticDrawer extends MenuDrawer {
public StaticDrawer(Context context) {
super(context);
}
public StaticDrawer(Context context, AttributeSet attrs) {
super(context, attrs);
}
public StaticDrawer(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void initDrawer(Context context, AttributeSet attrs, int defStyle) {
super.initDrawer(context, attrs, defStyle);
super.addView(mMenuContainer, -1, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
super.addView(mContentContainer, -1, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
mIsStatic = true;
}
@Override
protected void drawOverlay(Canvas canvas) {
// NO-OP
}
@Override
protected void onOffsetPixelsChanged(int offsetPixels) {
// NO-OP
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int width = r - l;
final int height = b - t;
switch (getPosition()) {
case LEFT:
mMenuContainer.layout(0, 0, mMenuSize, height);
mContentContainer.layout(mMenuSize, 0, width, height);
break;
case RIGHT:
mMenuContainer.layout(width - mMenuSize, 0, width, height);
mContentContainer.layout(0, 0, width - mMenuSize, height);
break;
case TOP:
mMenuContainer.layout(0, 0, width, mMenuSize);
mContentContainer.layout(0, mMenuSize, width, height);
break;
case BOTTOM:
mMenuContainer.layout(0, height - mMenuSize, width, height);
mContentContainer.layout(0, 0, width, height - mMenuSize);
break;
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (widthMode == MeasureSpec.UNSPECIFIED || heightMode == MeasureSpec.UNSPECIFIED) {
throw new IllegalStateException("Must measure with an exact size");
}
final int width = MeasureSpec.getSize(widthMeasureSpec);
final int height = MeasureSpec.getSize(heightMeasureSpec);
switch (getPosition()) {
case LEFT:
case RIGHT: {
final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
final int menuWidth = mMenuSize;
final int menuWidthMeasureSpec = MeasureSpec.makeMeasureSpec(menuWidth, MeasureSpec.EXACTLY);
final int contentWidth = width - menuWidth;
final int contentWidthMeasureSpec = MeasureSpec.makeMeasureSpec(contentWidth, MeasureSpec.EXACTLY);
mContentContainer.measure(contentWidthMeasureSpec, childHeightMeasureSpec);
mMenuContainer.measure(menuWidthMeasureSpec, childHeightMeasureSpec);
break;
}
case TOP:
case BOTTOM: {
final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
final int menuHeight = mMenuSize;
final int menuHeightMeasureSpec = MeasureSpec.makeMeasureSpec(menuHeight, MeasureSpec.EXACTLY);
final int contentHeight = height - menuHeight;
final int contentHeightMeasureSpec = MeasureSpec.makeMeasureSpec(contentHeight, MeasureSpec.EXACTLY);
mContentContainer.measure(childWidthMeasureSpec, contentHeightMeasureSpec);
mMenuContainer.measure(childWidthMeasureSpec, menuHeightMeasureSpec);
break;
}
}
setMeasuredDimension(width, height);
}
@Override
public void toggleMenu(boolean animate) {
// NO-OP
}
@Override
public void openMenu(boolean animate) {
// NO-OP
}
@Override
public void closeMenu(boolean animate) {
// NO-OP
}
@Override
public boolean isMenuVisible() {
return true;
}
@Override
public void setMenuSize(int size) {
mMenuSize = size;
requestLayout();
invalidate();
}
@Override
public void setOffsetMenuEnabled(boolean offsetMenu) {
// NO-OP
}
@Override
public boolean getOffsetMenuEnabled() {
return false;
}
@Override
public void peekDrawer() {
// NO-OP
}
@Override
public void peekDrawer(long delay) {
// NO-OP
}
@Override
public void peekDrawer(long startDelay, long delay) {
// NO-OP
}
@Override
public void setHardwareLayerEnabled(boolean enabled) {
// NO-OP
}
@Override
public int getTouchMode() {
return TOUCH_MODE_NONE;
}
@Override
public void setTouchMode(int mode) {
// NO-OP
}
@Override
public void setTouchBezelSize(int size) {
// NO-OP
}
@Override
public int getTouchBezelSize() {
return 0;
}
@Override
public void setSlideDrawable(int drawableRes) {
// NO-OP
}
@Override
public void setSlideDrawable(Drawable drawable) {
// NO-OP
}
@Override
public void setupUpIndicator(Activity activity) {
// NO-OP
}
@Override
public void setDrawerIndicatorEnabled(boolean enabled) {
// NO-OP
}
@Override
public boolean isDrawerIndicatorEnabled() {
return false;
}
}

View File

@ -1,50 +0,0 @@
package net.simonvt.menudrawer;
import android.os.Build;
import android.view.View;
final class ViewHelper {
private ViewHelper() {
}
public static int getLeft(View v) {
if (MenuDrawer.USE_TRANSLATIONS) {
return (int) (v.getLeft() + v.getTranslationX());
}
return v.getLeft();
}
public static int getTop(View v) {
if (MenuDrawer.USE_TRANSLATIONS) {
return (int) (v.getTop() + v.getTranslationY());
}
return v.getTop();
}
public static int getRight(View v) {
if (MenuDrawer.USE_TRANSLATIONS) {
return (int) (v.getRight() + v.getTranslationX());
}
return v.getRight();
}
public static int getBottom(View v) {
if (MenuDrawer.USE_TRANSLATIONS) {
return (int) (v.getBottom() + v.getTranslationY());
}
return v.getBottom();
}
public static int getLayoutDirection(View v) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
return v.getLayoutDirection();
}
return View.LAYOUT_DIRECTION_LTR;
}
}

View File

@ -1,79 +0,0 @@
package net.simonvt.menudrawer.compat;
import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.os.Build;
import timber.log.Timber;
import java.lang.reflect.Method;
public final class ActionBarHelper {
static final boolean DEBUG = false;
private Activity mActivity;
private Object mIndicatorInfo;
private boolean mUsesCompat;
public ActionBarHelper(Activity activity) {
mActivity = activity;
try {
Class clazz = activity.getClass();
Method m = clazz.getMethod("getSupportActionBar");
mUsesCompat = true;
} catch (NoSuchMethodException e) {
if (DEBUG) {
Timber.e(e,
"Activity " + activity.getClass().getSimpleName() + " does not use a compatibility action bar");
}
}
mIndicatorInfo = getIndicatorInfo();
}
private Object getIndicatorInfo() {
if (mUsesCompat && Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
return ActionBarHelperCompat.getIndicatorInfo(mActivity);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
return ActionBarHelperNative.getIndicatorInfo(mActivity);
}
return null;
}
public void setActionBarUpIndicator(Drawable drawable, int contentDesc) {
if (mUsesCompat && Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
ActionBarHelperCompat.setActionBarUpIndicator(mIndicatorInfo, mActivity, drawable, contentDesc);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
ActionBarHelperNative.setActionBarUpIndicator(mIndicatorInfo, mActivity, drawable, contentDesc);
}
}
public void setActionBarDescription(int contentDesc) {
if (mUsesCompat && Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
ActionBarHelperCompat.setActionBarDescription(mIndicatorInfo, mActivity, contentDesc);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
ActionBarHelperNative.setActionBarDescription(mIndicatorInfo, mActivity, contentDesc);
}
}
public Drawable getThemeUpIndicator() {
if (mUsesCompat && Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
return ActionBarHelperCompat.getThemeUpIndicator(mIndicatorInfo);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
return ActionBarHelperNative.getThemeUpIndicator(mIndicatorInfo, mActivity);
}
return null;
}
public void setDisplayShowHomeAsUpEnabled(boolean enabled) {
if (mUsesCompat && Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
ActionBarHelperCompat.setDisplayHomeAsUpEnabled(mIndicatorInfo, enabled);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
ActionBarHelperNative.setDisplayHomeAsUpEnabled(mActivity, enabled);
}
}
}

View File

@ -1,105 +0,0 @@
package net.simonvt.menudrawer.compat;
import android.app.Activity;
import android.graphics.drawable.Drawable;
import timber.log.Timber;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import java.lang.reflect.Method;
final class ActionBarHelperCompat {
private ActionBarHelperCompat() {
}
public static void setActionBarUpIndicator(Object info, Activity activity, Drawable drawable, int contentDescRes) {
final SetIndicatorInfo sii = (SetIndicatorInfo) info;
if (sii.mUpIndicatorView != null) {
sii.mUpIndicatorView.setImageDrawable(drawable);
final String contentDescription = contentDescRes == 0 ? null : activity.getString(contentDescRes);
sii.mUpIndicatorView.setContentDescription(contentDescription);
}
}
public static void setActionBarDescription(Object info, Activity activity, int contentDescRes) {
final SetIndicatorInfo sii = (SetIndicatorInfo) info;
if (sii.mUpIndicatorView != null) {
final String contentDescription = contentDescRes == 0 ? null : activity.getString(contentDescRes);
sii.mUpIndicatorView.setContentDescription(contentDescription);
}
}
public static Drawable getThemeUpIndicator(Object info) {
final SetIndicatorInfo sii = (SetIndicatorInfo) info;
if (sii.mUpIndicatorView != null) {
return sii.mUpIndicatorView.getDrawable();
}
return null;
}
public static Object getIndicatorInfo(Activity activity) {
return new SetIndicatorInfo(activity);
}
public static void setDisplayHomeAsUpEnabled(Object info, boolean enabled) {
final SetIndicatorInfo sii = (SetIndicatorInfo) info;
if (sii.mHomeAsUpEnabled != null) {
try {
sii.mHomeAsUpEnabled.invoke(sii.mActionBar, enabled);
} catch (Throwable t) {
if (ActionBarHelper.DEBUG) {
Timber.e(t, "Unable to call setHomeAsUpEnabled");
}
}
}
}
private static class SetIndicatorInfo {
public ImageView mUpIndicatorView;
public Object mActionBar;
public Method mHomeAsUpEnabled;
SetIndicatorInfo(Activity activity) {
try {
String appPackage = activity.getPackageName();
try {
// Attempt to find ActionBarSherlock up indicator
final int homeId = activity.getResources().getIdentifier("abs__home", "id", appPackage);
View v = activity.findViewById(homeId);
ViewGroup parent = (ViewGroup) v.getParent();
final int upId = activity.getResources().getIdentifier("abs__up", "id", appPackage);
mUpIndicatorView = (ImageView) parent.findViewById(upId);
} catch (Throwable t) {
if (ActionBarHelper.DEBUG) {
Timber.e(t,"ABS action bar not found");
}
}
if (mUpIndicatorView == null) {
// Attempt to find AppCompat up indicator
final int homeId = activity.getResources().getIdentifier("home", "id", appPackage);
View v = activity.findViewById(homeId);
ViewGroup parent = (ViewGroup) v.getParent();
final int upId = activity.getResources().getIdentifier("up", "id", appPackage);
mUpIndicatorView = (ImageView) parent.findViewById(upId);
}
Class supportActivity = activity.getClass();
Method getActionBar = supportActivity.getMethod("getSupportActionBar");
mActionBar = getActionBar.invoke(activity, (Object)null);
Class supportActionBar = mActionBar.getClass();
mHomeAsUpEnabled = supportActionBar.getMethod("setDisplayHomeAsUpEnabled", Boolean.TYPE);
} catch (Throwable t) {
if (ActionBarHelper.DEBUG) {
Timber.e(t, "Unable to init SetIndicatorInfo for ABS");
}
}
}
}
}

View File

@ -1,112 +0,0 @@
package net.simonvt.menudrawer.compat;
import android.app.ActionBar;
import android.app.Activity;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import timber.log.Timber;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import java.lang.reflect.Method;
final class ActionBarHelperNative {
private ActionBarHelperNative() {
}
private static final int[] THEME_ATTRS = new int[] {
android.R.attr.homeAsUpIndicator
};
public static void setActionBarUpIndicator(Object info, Activity activity, Drawable drawable, int contentDescRes) {
final SetIndicatorInfo sii = (SetIndicatorInfo) info;
if (sii.setHomeAsUpIndicator != null) {
try {
final ActionBar actionBar = activity.getActionBar();
sii.setHomeAsUpIndicator.invoke(actionBar, drawable);
sii.setHomeActionContentDescription.invoke(actionBar, contentDescRes);
} catch (Throwable t) {
if (ActionBarHelper.DEBUG) Timber.e(t, "Couldn't set home-as-up indicator via JB-MR2 API");
}
} else if (sii.upIndicatorView != null) {
sii.upIndicatorView.setImageDrawable(drawable);
} else {
if (ActionBarHelper.DEBUG) Timber.e("Couldn't set home-as-up indicator");
}
}
public static void setActionBarDescription(Object info, Activity activity, int contentDescRes) {
final SetIndicatorInfo sii = (SetIndicatorInfo) info;
if (sii.setHomeAsUpIndicator != null) {
try {
final ActionBar actionBar = activity.getActionBar();
sii.setHomeActionContentDescription.invoke(actionBar, contentDescRes);
} catch (Throwable t) {
if (ActionBarHelper.DEBUG) Timber.e(t, "Couldn't set content description via JB-MR2 API");
}
}
}
public static Drawable getThemeUpIndicator(Object info, Activity activity) {
final TypedArray a = activity.obtainStyledAttributes(THEME_ATTRS);
final Drawable result = a.getDrawable(0);
a.recycle();
return result;
}
public static Object getIndicatorInfo(Activity activity) {
return new SetIndicatorInfo(activity);
}
public static void setDisplayHomeAsUpEnabled(Activity activity, boolean b) {
ActionBar actionBar = activity.getActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(b);
}
}
private static class SetIndicatorInfo {
public Method setHomeAsUpIndicator;
public Method setHomeActionContentDescription;
public ImageView upIndicatorView;
SetIndicatorInfo(Activity activity) {
try {
setHomeAsUpIndicator = ActionBar.class.getDeclaredMethod("setHomeAsUpIndicator", Drawable.class);
setHomeActionContentDescription = ActionBar.class.getDeclaredMethod(
"setHomeActionContentDescription", Integer.TYPE);
// If we got the method we won't need the stuff below.
return;
} catch (Throwable t) {
// Oh well. We'll use the other mechanism below instead.
}
final View home = activity.findViewById(android.R.id.home);
if (home == null) {
// Action bar doesn't have a known configuration, an OEM messed with things.
return;
}
final ViewGroup parent = (ViewGroup) home.getParent();
final int childCount = parent.getChildCount();
if (childCount != 2) {
// No idea which one will be the right one, an OEM messed with things.
return;
}
final View first = parent.getChildAt(0);
final View second = parent.getChildAt(1);
final View up = first.getId() == android.R.id.home ? second : first;
if (up instanceof ImageView) {
// Jackpot! (Probably...)
upIndicatorView = (ImageView) up;
}
}
}
}

View File

@ -1,65 +0,0 @@
<resources>
<!-- Reference to a style for the menu drawer. -->
<attr name="menuDrawerStyle" format="reference" />
<!-- Styleables used for styling the menu drawer. -->
<declare-styleable name="MenuDrawer">
<!-- Drawable to use for the background of the content. -->
<attr name="mdContentBackground" format="reference" />
<!-- Drawable to use for the background of the menu. -->
<attr name="mdMenuBackground" format="reference" />
<!-- The size of the menu. -->
<attr name="mdMenuSize" format="dimension" />
<!-- Drawable used as indicator for the active view. -->
<attr name="mdActiveIndicator" format="reference" />
<!-- Defines whether the content will have a dropshadow onto the menu. Default is true. -->
<attr name="mdDropShadowEnabled" format="boolean" />
<!-- The size of the drop shadow. Default is 6dp -->
<attr name="mdDropShadowSize" format="dimension" />
<!-- The color of the drop shadow. Default is #FF000000. -->
<attr name="mdDropShadowColor" format="color" />
<!-- Drawable used for the drop shadow. -->
<attr name="mdDropShadow" format="reference" />
<!-- The touch bezel size. -->
<attr name="mdTouchBezelSize" format="dimension" />
<!-- Whether the indicator should be animated between active views. -->
<attr name="mdAllowIndicatorAnimation" format="boolean" />
<!-- The maximum animation duration -->
<attr name="mdMaxAnimationDuration" format="integer" />
<!-- Drawable that replaces the up indicator -->
<attr name="mdSlideDrawable" format="reference" />
<!-- String to use as the up indicators content description when the drawer is open -->
<attr name="mdDrawerOpenUpContentDescription" format="string" />
<!-- String to use as the up indicators content description when the drawer is closed -->
<attr name="mdDrawerClosedUpContentDescription" format="string" />
<!-- Whether an overlay should be drawn as the drawer is opened and closed -->
<attr name="mdDrawOverlay" format="boolean" />
<!-- The position of the drawer -->
<attr name="mdPosition" format="enum">
<enum name="left" value="0" />
<enum name="top" value="1" />
<enum name="right" value="2" />
<enum name="bottom" value="3" />
<enum name="start" value="4" />
<enum name="end" value="5" />
</attr>
</declare-styleable>
</resources>

View File

@ -1,6 +0,0 @@
<resources>
<!-- The default background of the menu. -->
<color name="md__defaultBackground">#FF555555</color>
</resources>

View File

@ -1,24 +0,0 @@
<resources>
<!-- ID used when defining the content layout in XML. -->
<item name="mdContent" type="id" />
<!-- ID used when defining the menu layout in XML. -->
<item name="mdMenu" type="id" />
<!-- The ID of the content container. -->
<item name="md__content" type="id" />
<!-- The ID of the menu container. -->
<item name="md__menu" type="id" />
<!-- The ID of the drawer. -->
<item name="md__drawer" type="id" />
<!-- Used with View#setTag(int) to specify a position for the active view. -->
<item name="mdActiveViewPosition" type="id" />
<item name="md__translationX" type="id" />
<item name="md__translationY" type="id" />
</resources>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
<string name="md__drawerOpenIndicatorDesc" tools:ignore="MissingTranslation">Close drawer</string>
<string name="md__drawerClosedIndicatorDesc" tools:ignore="MissingTranslation">Open drawer</string>
</resources>

View File

@ -1,13 +0,0 @@
<resources>
<style name="Widget" />
<!-- Base theme for the menu drawer. -->
<style name="Widget.MenuDrawer">
<item name="mdMenuBackground">@color/md__defaultBackground</item>
<item name="mdContentBackground">?android:attr/windowBackground</item>
<item name="mdDrawerOpenUpContentDescription">@string/md__drawerOpenIndicatorDesc</item>
<item name="mdDrawerClosedUpContentDescription">@string/md__drawerClosedIndicatorDesc</item>
</style>
</resources>

View File

@ -3,5 +3,4 @@ include ':core:domain'
include ':core:subsonic-api'
include ':core:subsonic-api-image-loader'
include ':core:cache'
include ':core:menudrawer'
include ':ultrasonic'

View File

@ -62,7 +62,6 @@ tasks.withType(Test) {
}
dependencies {
implementation project(':core:menudrawer')
implementation project(':core:library')
implementation project(':core:domain')
implementation project(':core:subsonic-api')

View File

@ -47,7 +47,7 @@
<service
android:name=".service.MediaPlayerService"
android:label="Ultrasonic Download Service"
android:label="Ultrasonic Media Player Service"
android:exported="false">
</service>
@ -125,10 +125,6 @@
android:name=".provider.SearchSuggestionProvider"
android:authorities="org.moire.ultrasonic.provider.SearchSuggestionProvider"/>
<meta-data
android:name="android.app.default_searchable"
android:value="org.moire.ultrasonic.activity.QueryReceiverActivity"/>
<receiver
android:name=".receiver.A2dpIntentReceiver"
android:exported="false">

View File

@ -262,6 +262,7 @@ public class ChatFragment extends Fragment {
private synchronized void load()
{
// TODO: Do we need a SwipeToRefresh progress indicator?
BackgroundTask<List<ChatMessage>> task = new TabActivityBackgroundTask<List<ChatMessage>>(getActivity(), false, null, cancellationToken)
{
@Override

View File

@ -83,7 +83,7 @@ public class PodcastFragment extends Fragment {
protected List<PodcastsChannel> doInBackground() throws Throwable
{
MusicService musicService = MusicServiceFactory.getMusicService(getContext());
return musicService.getPodcastsChannels(false,getContext(), this);
return musicService.getPodcastsChannels(false, getContext(), this);
/* TODO Why is here a cache cleaning? (original TODO text: c'est quoi ce nettoyage de cache ?)
if (!Util.isOffline(PodcastsActivity.this))

View File

@ -47,12 +47,13 @@ import timber.log.Timber
/**
* A simple activity demonstrating use of a NavHostFragment with a navigation drawer.
* The main Activity of Ultrasonic which loads all other screens as Fragments
*/
class NavigationActivity : AppCompatActivity() {
var chatMenuItem: MenuItem? = null
var bookmarksMenuItem: MenuItem? = null
var sharesMenuItem: MenuItem? = null
var podcastsMenuItem: MenuItem? = null
private var theme: String? = null
var nowPlayingView: FragmentContainerView? = null
var nowPlayingHidden = false
@ -115,6 +116,9 @@ class NavigationActivity : AppCompatActivity() {
if (!nowPlayingHidden) showNowPlaying()
}
// Hides menu items for Offline mode
setMenuForServerSetting()
// TODO: Maybe we can find a better place for theme change. Currently the change occurs when navigating between fragments
// but theoretically Settings could request a Navigation Activity recreate instantly when the theme setting changes
// Make sure to update theme if it has changed
@ -155,11 +159,8 @@ class NavigationActivity : AppCompatActivity() {
override fun onResume() {
super.onResume()
val visibility = !isOffline(this)
chatMenuItem?.isVisible = visibility
bookmarksMenuItem?.isVisible = visibility
sharesMenuItem?.isVisible = visibility
setMenuForServerSetting()
Util.registerMediaButtonEventReceiver(this, false)
// Lifecycle support's constructor registers some event receivers so it should be created early
lifecycleSupport.onCreate()
@ -169,12 +170,9 @@ class NavigationActivity : AppCompatActivity() {
}
override fun onDestroy() {
super.onDestroy()
Util.unregisterMediaButtonEventReceiver(this, false)
nowPlayingEventDistributor.unsubscribe(nowPlayingEventListener)
super.onDestroy()
// TODO: Handle NowPlaying if necessary
//nowPlayingView = null
imageLoaderProvider.clearImageLoader()
}
@ -207,9 +205,10 @@ class NavigationActivity : AppCompatActivity() {
true
}
chatMenuItem = sideNavView.menu.findItem(R.id.menu_chat)
bookmarksMenuItem = sideNavView.menu.findItem(R.id.menu_bookmarks)
sharesMenuItem = sideNavView.menu.findItem(R.id.menu_shares)
chatMenuItem = sideNavView.menu.findItem(R.id.chatFragment)
bookmarksMenuItem = sideNavView.menu.findItem(R.id.bookmarksFragment)
sharesMenuItem = sideNavView.menu.findItem(R.id.sharesFragment)
podcastsMenuItem = sideNavView.menu.findItem(R.id.podcastFragment)
}
private fun setupActionBar(navController: NavController, appBarConfig: AppBarConfiguration) {
@ -325,4 +324,12 @@ class NavigationActivity : AppCompatActivity() {
private fun hideNowPlaying() {
nowPlayingView?.visibility = View.GONE
}
private fun setMenuForServerSetting() {
val visibility = !isOffline(this)
chatMenuItem?.isVisible = visibility
bookmarksMenuItem?.isVisible = visibility
sharesMenuItem?.isVisible = visibility
podcastsMenuItem?.isVisible = visibility
}
}

View File

@ -4,15 +4,12 @@
a:layout_height="fill_parent"
a:orientation="vertical" >
<include layout="@layout/tab_progress" />
<ListView
a:id="@+id/chat_entries_list"
a:layout_width="fill_parent"
a:layout_height="0dip"
a:layout_weight="1.0" />
<LinearLayout
a:layout_height="4dip"
a:layout_width="fill_parent"

View File

@ -1,124 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/menu_main"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:alpha="1">
<TextView
android:id="@+id/menu_navigation"
style="@style/MenuDrawer.Widget.Category"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/menu.navigation"/>
<TextView
android:id="@+id/menu_home"
style="@style/MenuDrawer.Widget.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableLeft="?attr/home"
android:text="@string/button_bar.home"/>
<TextView
android:id="@+id/menu_browse"
style="@style/MenuDrawer.Widget.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableLeft="?attr/browse"
android:text="@string/button_bar.browse"/>
<TextView
android:id="@+id/menu_search"
style="@style/MenuDrawer.Widget.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableLeft="?attr/search"
android:text="@string/button_bar.search"/>
<TextView
android:id="@+id/menu_playlists"
style="@style/MenuDrawer.Widget.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableLeft="?attr/playlists"
android:text="@string/button_bar.playlists"/>
<TextView
android:id="@+id/menu_shares"
style="@style/MenuDrawer.Widget.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableLeft="?attr/share"
android:text="@string/button_bar.shares"/>
<TextView
android:id="@+id/menu_bookmarks"
style="@style/MenuDrawer.Widget.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableLeft="?attr/bookmark"
android:text="@string/button_bar.bookmarks"/>
<TextView
android:id="@+id/menu_chat"
style="@style/MenuDrawer.Widget.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableLeft="?attr/chat"
android:text="@string/button_bar.chat"/>
<TextView
android:id="@+id/menu_now_playing"
style="@style/MenuDrawer.Widget.Title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableLeft="?attr/media_play"
android:text="@string/button_bar.now_playing"/>
<TextView
android:id="@+id/menu_podcasts"
style="@style/MenuDrawer.Widget.Title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableLeft="?attr/podcasts"
android:text="@string/button_bar.podcasts"/>
<TextView
android:id="@+id/menu_common"
style="@style/MenuDrawer.Widget.Category"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/menu.common"/>
<TextView
android:id="@+id/menu_settings"
style="@style/MenuDrawer.Widget.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableLeft="?attr/settings"
android:text="@string/menu.settings"/>
<TextView
android:id="@+id/menu_about"
style="@style/MenuDrawer.Widget.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableLeft="?attr/about"
android:text="@string/menu.about"/>
<TextView
android:id="@+id/menu_exit"
style="@style/MenuDrawer.Widget.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableLeft="?attr/exit"
android:text="@string/menu.exit"/>
</LinearLayout>
</ScrollView>

View File

@ -4,8 +4,6 @@
a:layout_height="fill_parent"
a:orientation="vertical" >
<include layout="@layout/tab_progress" />
<TextView
a:id="@+id/select_podcasts_empty"
a:layout_width="fill_parent"

View File

@ -5,8 +5,6 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
a:orientation="vertical">
<include layout="@layout/tab_progress" />
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
a:id="@+id/select_artist_refresh"
a:layout_width="fill_parent"

View File

@ -4,8 +4,6 @@
a:layout_height="fill_parent"
a:orientation="vertical" >
<include layout="@layout/tab_progress" />
<TextView
a:id="@+id/select_genre_empty"
a:layout_width="fill_parent"

View File

@ -4,8 +4,6 @@
a:layout_height="fill_parent"
a:orientation="vertical" >
<include layout="@layout/tab_progress" />
<TextView
a:id="@+id/select_playlist_empty"
a:layout_width="fill_parent"

View File

@ -4,8 +4,6 @@
a:layout_height="fill_parent"
a:orientation="vertical">
<include layout="@layout/tab_progress" />
<TextView
a:id="@+id/select_share_empty"
a:layout_width="fill_parent"

View File

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/tab_progress"
a:layout_width="fill_parent"
a:layout_height="wrap_content"
a:layout_gravity="top"
a:orientation="horizontal"
a:padding="10dp"
a:visibility="gone" >
<ProgressBar
a:layout_width="16dp"
a:layout_height="16dp"
a:layout_gravity="center_vertical"
a:layout_marginRight="6dp" />
<TextView
a:id="@+id/tab_progress_message"
a:layout_width="wrap_content"
a:layout_height="wrap_content"
a:layout_gravity="center_vertical"
a:text="@string/progress.wait" />
</LinearLayout>

View File

@ -1,14 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Widget.MenuDrawer">
<item name="mdMenuBackground">?android:attr/windowBackground</item>
<item name="mdContentBackground">?android:attr/windowBackground</item>
<item name="mdActiveIndicator">@drawable/menu_arrow</item>
<item name="mdDropShadowSize">5dip</item>
<item name="mdDropShadowColor">@color/translucent</item>
<item name="mdAllowIndicatorAnimation">true</item>
</style>
<style name="NoActionBar" parent="@style/Theme.AppCompat">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
@ -29,17 +20,6 @@
<item name="android:ellipsize">end</item>
</style>
<style name="MenuDrawer.Widget.Title">
<item name="android:textAppearance">?android:attr/textAppearance</item>
<item name="android:textSize">18sp</item>
<item name="android:paddingLeft">16dp</item>
<item name="android:paddingRight">32dp</item>
<item name="android:paddingTop">8dp</item>
<item name="android:paddingBottom">8dp</item>
<item name="android:drawablePadding">16dp</item>
<item name="android:gravity">center_vertical</item>
</style>
<style name="roundedImageView" parent="">
<item name="cornerFamily">rounded</item>
<item name="cornerSize">8dp</item>