Refactor to allow for snooze reminders (snooze when user hits the back or home buttons).

This commit is contained in:
Timothy Allen 2014-03-27 21:15:27 +02:00
parent c2806f2231
commit 1813f3faa6
57 changed files with 4737 additions and 94 deletions

1
GlowPadBackport/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

View File

@ -71,6 +71,7 @@
</content> </content>
<orderEntry type="jdk" jdkName="Android API 19 Platform" jdkType="Android SDK" /> <orderEntry type="jdk" jdkName="Android API 19 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" exported="" name="library-2.4.0" level="project" />
</component> </component>
</module> </module>

View File

@ -5,8 +5,8 @@ android {
buildToolsVersion "19.0.1" buildToolsVersion "19.0.1"
defaultConfig { defaultConfig {
minSdkVersion 10 minSdkVersion 8
targetSdkVersion 19 targetSdkVersion 16
versionCode 1 versionCode 1
versionName "1.0" versionName "1.0"
} }
@ -17,3 +17,7 @@ android {
} }
} }
} }
dependencies {
compile 'com.nineoldandroids:library:2.4.0'
}

View File

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.sebastianopoggi.ui.GlowPadBackport"> package="net.sebastianopoggi.ui.GlowPadBackport" >
</manifest> <application />
</manifest>

View File

@ -0,0 +1,134 @@
/*
* Copyright (C) 2011 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.sebastianopoggi.ui.GlowPadBackport;
import net.sebastianopoggi.ui.GlowPadBackport.util.TimeInterpolator;
class Ease {
private static final float DOMAIN = 1.0f;
private static final float DURATION = 1.0f;
private static final float START = 0.0f;
static class Linear {
public static final TimeInterpolator easeNone = new TimeInterpolator() {
public float getInterpolation(float input) {
return input;
}
};
}
static class Cubic {
public static final TimeInterpolator easeIn = new TimeInterpolator() {
public float getInterpolation(float input) {
return DOMAIN * (input /= DURATION) * input * input + START;
}
};
public static final TimeInterpolator easeOut = new TimeInterpolator() {
public float getInterpolation(float input) {
return DOMAIN * ((input = input / DURATION - 1) * input * input + 1) + START;
}
};
public static final TimeInterpolator easeInOut = new TimeInterpolator() {
public float getInterpolation(float input) {
return ((input /= DURATION / 2) < 1.0f) ?
(DOMAIN / 2 * input * input * input + START)
: (DOMAIN / 2 * ((input -= 2) * input * input + 2) + START);
}
};
}
static class Quad {
public static final TimeInterpolator easeIn = new TimeInterpolator() {
public float getInterpolation(float input) {
return DOMAIN * (input /= DURATION) * input + START;
}
};
public static final TimeInterpolator easeOut = new TimeInterpolator() {
public float getInterpolation(float input) {
return -DOMAIN * (input /= DURATION) * (input - 2) + START;
}
};
public static final TimeInterpolator easeInOut = new TimeInterpolator() {
public float getInterpolation(float input) {
return ((input /= DURATION / 2) < 1) ?
(DOMAIN / 2 * input * input + START)
: (-DOMAIN / 2 * ((--input) * (input - 2) - 1) + START);
}
};
}
static class Quart {
public static final TimeInterpolator easeIn = new TimeInterpolator() {
public float getInterpolation(float input) {
return DOMAIN * (input /= DURATION) * input * input * input + START;
}
};
public static final TimeInterpolator easeOut = new TimeInterpolator() {
public float getInterpolation(float input) {
return -DOMAIN * ((input = input / DURATION - 1) * input * input * input - 1) + START;
}
};
public static final TimeInterpolator easeInOut = new TimeInterpolator() {
public float getInterpolation(float input) {
return ((input /= DURATION / 2) < 1) ?
(DOMAIN / 2 * input * input * input * input + START)
:
(-DOMAIN / 2 * ((input -= 2) * input * input * input - 2) + START);
}
};
}
static class Quint {
public static final TimeInterpolator easeIn = new TimeInterpolator() {
public float getInterpolation(float input) {
return DOMAIN * (input /= DURATION) * input * input * input * input + START;
}
};
public static final TimeInterpolator easeOut = new TimeInterpolator() {
public float getInterpolation(float input) {
return DOMAIN * ((input = input / DURATION - 1) * input * input * input * input + 1) + START;
}
};
public static final TimeInterpolator easeInOut = new TimeInterpolator() {
public float getInterpolation(float input) {
return ((input /= DURATION / 2) < 1) ?
(DOMAIN / 2 * input * input * input * input * input + START)
:
(DOMAIN / 2 * ((input -= 2) * input * input * input * input + 2) + START);
}
};
}
static class Sine {
public static final TimeInterpolator easeIn = new TimeInterpolator() {
public float getInterpolation(float input) {
return -DOMAIN * (float) Math.cos(input / DURATION * (Math.PI / 2)) + DOMAIN + START;
}
};
public static final TimeInterpolator easeOut = new TimeInterpolator() {
public float getInterpolation(float input) {
return DOMAIN * (float) Math.sin(input / DURATION * (Math.PI / 2)) + START;
}
};
public static final TimeInterpolator easeInOut = new TimeInterpolator() {
public float getInterpolation(float input) {
return -DOMAIN / 2 * ((float) Math.cos(Math.PI * input / DURATION) - 1.0f) + START;
}
};
}
}

View File

@ -0,0 +1,247 @@
/*
* Copyright (C) 2012 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.sebastianopoggi.ui.GlowPadBackport;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.util.FloatMath;
import android.util.Log;
import java.util.ArrayList;
public class PointCloud {
private static final float MIN_POINT_SIZE = 2.0f;
private static final float MAX_POINT_SIZE = 4.0f;
private static int INNER_POINTS = 8;
private static final String TAG = "PointCloud";
private ArrayList<Point> mPointCloud = new ArrayList<Point>();
private Drawable mDrawable;
private float mCenterX;
private float mCenterY;
private Paint mPaint;
private float mScale = 1.0f;
private static final float PI = (float) Math.PI;
// These allow us to have multiple concurrent animations.
WaveManager waveManager = new WaveManager();
GlowManager glowManager = new GlowManager();
private float mOuterRadius, mInnerRadius;
public class WaveManager {
private float radius = 50;
private float width = 200.0f; // TODO: Make configurable
private float alpha = 0.0f;
public void setRadius(float r) {
radius = r;
}
public float getRadius() {
return radius;
}
public void setAlpha(float a) {
alpha = a;
}
public float getAlpha() {
return alpha;
}
}
public class GlowManager {
private float x;
private float y;
private float radius = 0.0f;
private float alpha = 0.0f;
public void setX(float x1) {
x = x1;
}
public float getX() {
return x;
}
public void setY(float y1) {
y = y1;
}
public float getY() {
return y;
}
public void setAlpha(float a) {
alpha = a;
}
public float getAlpha() {
return alpha;
}
public void setRadius(float r) {
radius = r;
}
public float getRadius() {
return radius;
}
}
class Point {
float x;
float y;
float radius;
public Point(float x2, float y2, float r) {
x = x2;
y = y2;
radius = r;
}
}
public PointCloud(Drawable drawable) {
mPaint = new Paint();
mPaint.setFilterBitmap(true);
mPaint.setColor(Color.rgb(255, 255, 255)); // TODO: make configurable
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mDrawable = drawable;
if (mDrawable != null) {
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
}
}
/*package*/ void setPointsMultiplier(int mult) {
INNER_POINTS = mult;
makePointCloud(mInnerRadius, mOuterRadius);
}
/*package*/ int getPointsMultiplier() {
return INNER_POINTS;
}
public void setCenter(float x, float y) {
mCenterX = x;
mCenterY = y;
}
public void makePointCloud(float innerRadius, float outerRadius) {
if (innerRadius == 0) {
Log.w(TAG, "Must specify an inner radius");
return;
}
mOuterRadius = outerRadius;
mInnerRadius = innerRadius;
mPointCloud.clear();
final float pointAreaRadius = (outerRadius - innerRadius);
final float ds = (2.0f * PI * innerRadius / INNER_POINTS);
final int bands = Math.round(pointAreaRadius / ds);
final float dr = pointAreaRadius / bands;
float r = innerRadius;
for (int b = 0; b <= bands; b++, r += dr) {
float circumference = 2.0f * PI * r;
final int pointsInBand = (int) (circumference / ds);
float eta = PI / 2.0f;
float dEta = 2.0f * PI / pointsInBand;
for (int i = 0; i < pointsInBand; i++) {
float x = r * FloatMath.cos(eta);
float y = r * FloatMath.sin(eta);
eta += dEta;
mPointCloud.add(new Point(x, y, r));
}
}
}
public void setScale(float scale) {
mScale = scale;
}
public float getScale() {
return mScale;
}
private static float hypot(float x, float y) {
return FloatMath.sqrt(x * x + y * y);
}
private static float max(float a, float b) {
return a > b ? a : b;
}
public int getAlphaForPoint(Point point) {
// Contribution from positional glow
float glowDistance = hypot(glowManager.x - point.x, glowManager.y - point.y);
float glowAlpha = 0.0f;
if (glowDistance < glowManager.radius) {
float cosf = FloatMath.cos(PI * 0.25f * glowDistance / glowManager.radius);
glowAlpha = glowManager.alpha * max(0.0f, (float) Math.pow(cosf, 10.0f));
}
// Compute contribution from Wave
float radius = hypot(point.x, point.y);
float distanceToWaveRing = (radius - waveManager.radius);
float waveAlpha = 0.0f;
if (distanceToWaveRing < waveManager.width * 0.5f && distanceToWaveRing < 0.0f) {
float cosf = FloatMath.cos(PI * 0.25f * distanceToWaveRing / waveManager.width);
waveAlpha = waveManager.alpha * max(0.0f, (float) Math.pow(cosf, 20.0f));
}
return (int) (max(glowAlpha, waveAlpha) * 255);
}
private float interp(float min, float max, float f) {
return min + (max - min) * f;
}
public void draw(Canvas canvas) {
ArrayList<Point> points = mPointCloud;
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.scale(mScale, mScale, mCenterX, mCenterY);
for (int i = 0; i < points.size(); i++) {
Point point = points.get(i);
final float pointSize = interp(MAX_POINT_SIZE, MIN_POINT_SIZE,
point.radius / mOuterRadius);
final float px = point.x + mCenterX;
final float py = point.y + mCenterY;
int alpha = getAlphaForPoint(point);
if (alpha == 0) continue;
if (mDrawable != null) {
canvas.save(Canvas.MATRIX_SAVE_FLAG);
final float cx = mDrawable.getIntrinsicWidth() * 0.5f;
final float cy = mDrawable.getIntrinsicHeight() * 0.5f;
final float s = pointSize / MAX_POINT_SIZE;
canvas.scale(s, s, px, py);
canvas.translate(px - cx, py - cy);
mDrawable.setAlpha(alpha);
mDrawable.draw(canvas);
canvas.restore();
}
else {
mPaint.setAlpha(alpha);
canvas.drawCircle(px, py, pointSize, mPaint);
}
}
canvas.restore();
}
}

View File

@ -0,0 +1,341 @@
/*
* Copyright (C) 2011 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.sebastianopoggi.ui.GlowPadBackport;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.StateListDrawable;
import android.util.Log;
import java.lang.reflect.Method;
public class TargetDrawable {
private static final String TAG = "TargetDrawable";
private static final boolean DEBUG = false;
public static final int[] STATE_ACTIVE =
{android.R.attr.state_enabled, android.R.attr.state_active};
public static final int[] STATE_INACTIVE =
{android.R.attr.state_enabled, -android.R.attr.state_active};
public static final int[] STATE_FOCUSED =
{android.R.attr.state_enabled, -android.R.attr.state_active,
android.R.attr.state_focused};
// We're using Reflection to access these private APIs on older Android versions
static Method mGetStateDrawableIndex, mGetStateCount, mGetStateDrawable;
static {
// In this static block we initialize all reflected methods (so that we can work around
// the @hide annotations for those Android Framework methods). This is not ideal, but
// there's not much we can do about that either.
try {
mGetStateCount = StateListDrawable.class.getDeclaredMethod("getStateCount");
mGetStateCount.setAccessible(true);
}
catch (NoSuchMethodException e) {
Log.e(TAG, "Couldn't access the StateListDrawable#getStateCount() method. " +
"Some stuff might break!", e);
}
try {
mGetStateDrawable = StateListDrawable.class.getDeclaredMethod("getStateDrawable", int.class);
mGetStateDrawable.setAccessible(true);
}
catch (NoSuchMethodException e) {
Log.e(TAG, "Couldn't access the StateListDrawable#getStateDrawable(int) method. " +
"Some stuff might break!", e);
}
try {
mGetStateDrawableIndex = StateListDrawable.class.getDeclaredMethod("getStateDrawableIndex", int[].class);
mGetStateDrawableIndex.setAccessible(true);
}
catch (NoSuchMethodException e) {
Log.e(TAG, "Couldn't access the StateListDrawable#mGetStateDrawableIndex(int[]) method. " +
"Some stuff might break!", e);
}
}
private float mTranslationX = 0.0f;
private float mTranslationY = 0.0f;
private float mPositionX = 0.0f;
private float mPositionY = 0.0f;
private float mScaleX = 1.0f;
private float mScaleY = 1.0f;
private float mAlpha = 1.0f;
private Drawable mDrawable;
private boolean mEnabled = true;
private final int mResourceId;
/* package */ static class DrawableWithAlpha extends Drawable {
private float mAlpha = 1.0f;
private Drawable mRealDrawable;
public DrawableWithAlpha(Drawable realDrawable) {
mRealDrawable = realDrawable;
}
public void setAlphaFloat(float alpha) {
mAlpha = alpha;
}
public int getAlphaFloat() {
return (int) (mAlpha * 255);
}
public void draw(Canvas canvas) {
mRealDrawable.setAlpha(Math.round(mAlpha * 255f));
mRealDrawable.draw(canvas);
}
@Override
public void setAlpha(int alpha) {
mRealDrawable.setAlpha(alpha);
}
@Override
public int getAlpha() {
return mRealDrawable.getAlpha();
}
@Override
public void setColorFilter(ColorFilter cf) {
mRealDrawable.setColorFilter(cf);
}
@Override
public int getOpacity() {
return mRealDrawable.getOpacity();
}
}
public TargetDrawable(Resources res, int resId) {
mResourceId = resId;
setDrawable(res, resId);
}
public void setDrawable(Resources res, int resId) {
// Note we explicitly don't set mResourceId to resId since we allow the drawable to be
// swapped at runtime and want to re-use the existing resource id for identification.
Drawable drawable = resId == 0 ? null : res.getDrawable(resId);
// Mutate the drawable so we can animate shared drawable properties.
mDrawable = drawable != null ? drawable.mutate() : null;
resizeDrawables();
setState(STATE_INACTIVE);
}
public TargetDrawable(TargetDrawable other) {
mResourceId = other.mResourceId;
// Mutate the drawable so we can animate shared drawable properties.
mDrawable = other.mDrawable != null ? other.mDrawable.mutate() : null;
resizeDrawables();
setState(STATE_INACTIVE);
}
public void setState(int[] state) {
if (mDrawable instanceof StateListDrawable) {
StateListDrawable d = (StateListDrawable) mDrawable;
d.setState(state);
}
}
public boolean hasState(int[] state) {
if (mDrawable instanceof StateListDrawable) {
StateListDrawable d = (StateListDrawable) mDrawable;
// TODO: this doesn't seem to work
try {
return (Integer) mGetStateDrawableIndex.invoke(d, state) != -1;
}
catch (Exception e) {
Log.w(TAG, "StateListDrawable#getStateDrawableIndex(int[]) call failed!", e);
}
}
return false;
}
/**
* Returns true if the drawable is a StateListDrawable and is in the focused state.
*
* @return Returns true if the drawable is a StateListDrawable and is in the focused state
*/
public boolean isActive() {
if (mDrawable instanceof StateListDrawable) {
StateListDrawable d = (StateListDrawable) mDrawable;
int[] states = d.getState();
for (int i = 0; i < states.length; i++) {
if (states[i] == android.R.attr.state_focused) {
return true;
}
}
}
return false;
}
/**
* Returns true if this target is enabled. Typically an enabled target contains a valid
* drawable in a valid state. Currently all targets with valid drawables are valid.
*
* @return Returns true if the target is enabled, false otherwise
*/
public boolean isEnabled() {
return mDrawable != null && mEnabled;
}
/**
* Makes drawables in a StateListDrawable all the same dimensions.
* If not a StateListDrawable, then justs sets the bounds to the intrinsic size of the
* drawable.
*/
private void resizeDrawables() {
if (mDrawable instanceof StateListDrawable) {
StateListDrawable d = (StateListDrawable) mDrawable;
int maxWidth = 0;
int maxHeight = 0;
Integer stateCount = 0;
try {
stateCount = (Integer) mGetStateCount.invoke(d);
}
catch (Exception e) {
Log.w(TAG, "StateListDrawable#getStateCount() call failed!", e);
}
for (int i = 0; i < stateCount; i++) {
Drawable childDrawable;
try {
childDrawable = (Drawable) mGetStateDrawable.invoke(d, i);
}
catch (Exception e) {
Log.w(TAG, "StateListDrawable#getStateDrawable(int) call failed!", e);
continue;
}
maxWidth = Math.max(maxWidth, childDrawable.getIntrinsicWidth());
maxHeight = Math.max(maxHeight, childDrawable.getIntrinsicHeight());
}
if (DEBUG) {
Log.v(TAG, "union of childDrawable rects " + d + " to: "
+ maxWidth + "x" + maxHeight);
}
d.setBounds(0, 0, maxWidth, maxHeight);
for (int i = 0; i < stateCount; i++) {
Drawable childDrawable;
try {
childDrawable = (Drawable) mGetStateDrawable.invoke(d, i);
}
catch (Exception e) {
Log.w(TAG, "StateListDrawable#getStateDrawable(int) call failed!", e);
continue;
}
if (DEBUG) {
Log.v(TAG, "sizing drawable " + childDrawable + " to: "
+ maxWidth + "x" + maxHeight);
}
childDrawable.setBounds(0, 0, maxWidth, maxHeight);
}
}
else if (mDrawable != null) {
mDrawable.setBounds(0, 0,
mDrawable.getIntrinsicWidth(), mDrawable.getIntrinsicHeight());
}
}
public void setX(float x) {
mTranslationX = x;
}
public void setY(float y) {
mTranslationY = y;
}
public void setScaleX(float x) {
mScaleX = x;
}
public void setScaleY(float y) {
mScaleY = y;
}
public void setAlpha(float alpha) {
mAlpha = alpha;
}
public float getX() {
return mTranslationX;
}
public float getY() {
return mTranslationY;
}
public float getScaleX() {
return mScaleX;
}
public float getScaleY() {
return mScaleY;
}
public float getAlpha() {
return mAlpha;
}
public void setPositionX(float x) {
mPositionX = x;
}
public void setPositionY(float y) {
mPositionY = y;
}
public float getPositionX() {
return mPositionX;
}
public float getPositionY() {
return mPositionY;
}
public int getWidth() {
return mDrawable != null ? mDrawable.getIntrinsicWidth() : 0;
}
public int getHeight() {
return mDrawable != null ? mDrawable.getIntrinsicHeight() : 0;
}
public void draw(Canvas canvas) {
if (mDrawable == null || !mEnabled) {
return;
}
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.scale(mScaleX, mScaleY, mPositionX, mPositionY);
canvas.translate(mTranslationX + mPositionX, mTranslationY + mPositionY);
canvas.translate(-0.5f * getWidth(), -0.5f * getHeight());
mDrawable.setAlpha(Math.round(mAlpha * 255f));
mDrawable.draw(canvas);
canvas.restore();
}
public void setEnabled(boolean enabled) {
mEnabled = enabled;
}
public int getResourceId() {
return mResourceId;
}
}

View File

@ -0,0 +1,190 @@
/*
* Copyright (C) 2011 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.sebastianopoggi.ui.GlowPadBackport;
import android.util.Log;
import com.nineoldandroids.animation.Animator;
import com.nineoldandroids.animation.Animator.AnimatorListener;
import com.nineoldandroids.animation.AnimatorListenerAdapter;
import com.nineoldandroids.animation.ObjectAnimator;
import com.nineoldandroids.animation.PropertyValuesHolder;
import com.nineoldandroids.animation.ValueAnimator.AnimatorUpdateListener;
import net.sebastianopoggi.ui.GlowPadBackport.util.TimeInterpolator;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
class Tweener {
private static final String TAG = "Tweener";
private static final boolean DEBUG = false;
ObjectAnimator animator;
private static HashMap<Object, Tweener> sTweens = new HashMap<Object, Tweener>();
public Tweener(ObjectAnimator anim) {
animator = anim;
}
private static void remove(Animator animator) {
Iterator<Entry<Object, Tweener>> iter = sTweens.entrySet().iterator();
while (iter.hasNext()) {
Entry<Object, Tweener> entry = iter.next();
if (entry.getValue().animator == animator) {
if (DEBUG) {
Log.v(TAG, "Removing tweener " + sTweens.get(entry.getKey())
+ " sTweens.size() = " + sTweens.size());
}
iter.remove();
break; // an animator can only be attached to one object
}
}
}
public static Tweener to(Object object, long duration, Object... vars) {
long delay = 0;
AnimatorUpdateListener updateListener = null;
AnimatorListener listener = null;
TimeInterpolator interpolator = null;
// Iterate through arguments and discover properties to animate
ArrayList<PropertyValuesHolder> props = new ArrayList<PropertyValuesHolder>(vars.length / 2);
for (int i = 0; i < vars.length; i += 2) {
if (!(vars[i] instanceof String)) {
throw new IllegalArgumentException("Key must be a string: " + vars[i]);
}
String key = (String) vars[i];
Object value = vars[i + 1];
if ("simultaneousTween".equals(key)) {
// TODO
}
else if ("ease".equals(key)) {
interpolator = (TimeInterpolator) value; // TODO: multiple interpolators?
}
else if ("onUpdate".equals(key) || "onUpdateListener".equals(key)) {
updateListener = (AnimatorUpdateListener) value;
}
else if ("onComplete".equals(key) || "onCompleteListener".equals(key)) {
listener = (AnimatorListener) value;
}
else if ("delay".equals(key)) {
delay = ((Number) value).longValue();
}
else if ("syncWith".equals(key)) {
// TODO
}
else if (value instanceof float[]) {
props.add(PropertyValuesHolder.ofFloat(key,
((float[]) value)[0], ((float[]) value)[1]));
}
else if (value instanceof int[]) {
props.add(PropertyValuesHolder.ofInt(key,
((int[]) value)[0], ((int[]) value)[1]));
}
else if (value instanceof Number) {
float floatValue = ((Number) value).floatValue();
props.add(PropertyValuesHolder.ofFloat(key, floatValue));
}
else {
throw new IllegalArgumentException(
"Bad argument for key \"" + key + "\" with value " + value.getClass());
}
}
// Re-use existing tween, if present
Tweener tween = sTweens.get(object);
ObjectAnimator anim;
if (tween == null) {
anim = ObjectAnimator.ofPropertyValuesHolder(object,
props.toArray(new PropertyValuesHolder[props.size()]));
tween = new Tweener(anim);
sTweens.put(object, tween);
if (DEBUG) Log.v(TAG, "Added new Tweener " + tween);
}
else {
anim = sTweens.get(object).animator;
replace(props, object); // Cancel all animators for given object
}
if (interpolator != null) {
anim.setInterpolator(interpolator);
}
// Update animation with properties discovered in loop above
anim.setStartDelay(delay);
anim.setDuration(duration);
if (updateListener != null) {
anim.removeAllUpdateListeners(); // There should be only one
anim.addUpdateListener(updateListener);
}
if (listener != null) {
anim.removeAllListeners(); // There should be only one.
anim.addListener(listener);
}
anim.addListener(mCleanupListener);
return tween;
}
Tweener from(Object object, long duration, Object... vars) {
// TODO: for v of vars
// toVars[v] = object[v]
// object[v] = vars[v]
return Tweener.to(object, duration, vars);
}
// Listener to watch for completed animations and remove them.
private static AnimatorListener mCleanupListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
remove(animation);
}
@Override
public void onAnimationCancel(Animator animation) {
remove(animation);
}
};
public static void reset() {
if (DEBUG) {
Log.v(TAG, "Reset()");
if (sTweens.size() > 0) {
Log.v(TAG, "Cleaning up " + sTweens.size() + " animations");
}
}
sTweens.clear();
}
private static void replace(ArrayList<PropertyValuesHolder> props, Object... args) {
for (final Object killobject : args) {
Tweener tween = sTweens.get(killobject);
if (tween != null) {
tween.animator.cancel();
if (props != null) {
tween.animator.setValues(
props.toArray(new PropertyValuesHolder[props.size()]));
}
else {
sTweens.remove(tween);
}
}
}
}
}

View File

@ -0,0 +1,22 @@
package net.sebastianopoggi.ui.GlowPadBackport.util;
import android.os.Build;
/**
* Class
* <p/>
* Author: Sebastiano Poggi
* Created on: 1/28/13 Time: 3:57 PM
* File version: 1.0
* <p/>
* Changelog:
* Version 1.0
* * Initial revision
*/
public class Const {
public static final boolean IS_ECLAIR = Build.VERSION.SDK_INT >= Build.VERSION_CODES.ECLAIR;
public static final boolean IS_FROYO = Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO;
public static final boolean IS_ICS = Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH;
public static final boolean IS_JB = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
public static final boolean IS_JB_MR1 = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1;
}

View File

@ -0,0 +1,40 @@
/*
* Copyright (C) 2010 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.sebastianopoggi.ui.GlowPadBackport.util;
import android.view.animation.Interpolator;
/**
* A time interpolator defines the rate of change of an animation. This allows animations
* to have non-linear motion, such as acceleration and deceleration.
*/
public interface TimeInterpolator extends Interpolator {
/**
* Maps a value representing the elapsed fraction of an animation to a value that represents
* the interpolated fraction. This interpolated value is then multiplied by the change in
* value of an animation to derive the animated value at the current elapsed animation time.
*
* @param input A value between 0 and 1.0 indicating our current point
* in the animation where 0 represents the start and 1.0 represents
* the end
* @return The interpolation value. This value can be more than 1.0 for
* interpolators which overshoot their targets, or less than 0 for
* interpolators that undershoot their targets.
*/
float getInterpolation(float input);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

View File

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="LinearLayout">
<attr name="gravity" />
</declare-styleable>
<!-- =============================== -->
<!-- GlowPadView class attributes -->
<!-- =============================== -->
<eat-comment />
<declare-styleable name="GlowPadView">
<!-- Reference to an array resource that be shown as targets around a circle. -->
<attr name="targetDrawables" format="reference"/>
<!-- Reference to an array resource that be used as description for the targets around the circle. -->
<attr name="targetDescriptions" format="reference"/>
<!-- Reference to an array resource that be used to announce the directions with targets around the circle. -->
<attr name="directionDescriptions" format="reference"/>
<!-- Sets a drawable as the center. -->
<attr name="handleDrawable" format="reference"/>
<!-- Drawable to use for wave ripple animation. -->
<attr name="outerRingDrawable" format="reference"/>
<!-- Drawble used for drawing points -->
<attr name="pointDrawable" format="reference" />
<!-- Inner radius of glow area. -->
<attr name="innerRadius" format="dimension"/>
<!-- Outer radius of glow area. Target icons will be drawn on this circle. -->
<attr name="outerRadius" format="dimension"/>
<!-- Radius of glow under finger. -->
<attr name="glowRadius" format="dimension" />
<!-- Tactile feedback duration for actions. Set to '0' for no vibration. -->
<attr name="vibrationDuration" format="integer"/>
<!-- How close we need to be before snapping to a target. -->
<attr name="snapMargin" format="dimension"/>
<!-- Number of waves/chevrons to show in animation. -->
<attr name="feedbackCount" format="integer"/>
<!-- Used when the handle shouldn't wait to be hit before following the finger -->
<attr name="alwaysTrackFinger" format="boolean"/>
<!-- Location along the circle of the first item, in degrees.-->
<attr name="firstItemOffset" format="float" />
<!-- Causes targets to snap to the finger location on activation. -->
<attr name="magneticTargets" format="boolean" />
<attr name="gravity"/>
<!-- Determine whether the glow pad is allowed to scale to fit the bounds indicated
by its parent. If this is set to false, no scaling will occur. If this is set to true
scaling will occur to fit for any axis in which gravity is set to center. -->
<attr name="allowScaling" format="boolean" />
</declare-styleable>
<!-- Specifies how to place the content of an object, both
on the x and y axis, within the object itself. -->
<attr name="gravity">
<!-- Push object to the top of its container, not changing its size. -->
<flag name="top" value="0x30" />
<!-- Push object to the bottom of its container, not changing its size. -->
<flag name="bottom" value="0x50" />
<!-- Push object to the left of its container, not changing its size. -->
<flag name="left" value="0x03" />
<!-- Push object to the right of its container, not changing its size. -->
<flag name="right" value="0x05" />
<!-- Place object in the vertical center of its container, not changing its size. -->
<flag name="center_vertical" value="0x10" />
<!-- Grow the vertical size of the object if needed so it completely fills its container. -->
<flag name="fill_vertical" value="0x70" />
<!-- Place object in the horizontal center of its container, not changing its size. -->
<flag name="center_horizontal" value="0x01" />
<!-- Grow the horizontal size of the object if needed so it completely fills its container. -->
<flag name="fill_horizontal" value="0x07" />
<!-- Place the object in the center of its container in both the vertical and horizontal axis, not changing its size. -->
<flag name="center" value="0x11" />
<!-- Grow the horizontal and vertical size of the object if needed so it completely fills its container. -->
<flag name="fill" value="0x77" />
<!-- Additional option that can be set to have the top and/or bottom edges of
the child clipped to its container's bounds.
The clip will be based on the vertical gravity: a top gravity will clip the bottom
edge, a bottom gravity will clip the top edge, and neither will clip both edges. -->
<flag name="clip_vertical" value="0x80" />
<!-- Additional option that can be set to have the left and/or right edges of
the child clipped to its container's bounds.
The clip will be based on the horizontal gravity: a left gravity will clip the right
edge, a right gravity will clip the left edge, and neither will clip both edges. -->
<flag name="clip_horizontal" value="0x08" />
</attr>
</resources>

View File

@ -1,3 +0,0 @@
<resources>
<string name="app_name">GlowPadBackport</string>
</resources>

View File

@ -73,6 +73,8 @@
<orderEntry type="library" exported="" name="appcompat-v7-19.0.1" level="project" /> <orderEntry type="library" exported="" name="appcompat-v7-19.0.1" level="project" />
<orderEntry type="library" exported="" name="support-v4-19.0.1" level="project" /> <orderEntry type="library" exported="" name="support-v4-19.0.1" level="project" />
<orderEntry type="library" exported="" name="library-2.4.0" level="project" /> <orderEntry type="library" exported="" name="library-2.4.0" level="project" />
<orderEntry type="module" module-name="SeekArc" exported="" />
<orderEntry type="module" module-name="GlowPadBackport" exported="" />
</component> </component>
</module> </module>

View File

@ -17,11 +17,16 @@ android {
} }
} }
} }
repositories {
flatDir {
dirs 'libs'
}
}
dependencies { dependencies {
compile 'com.android.support:support-v4:19.0.1' compile 'com.android.support:support-v4:19.0.1'
compile 'com.android.support:appcompat-v7:19.0.1' compile 'com.android.support:appcompat-v7:19.0.1'
compile 'com.nineoldandroids:library:2.4.0'
compile fileTree(dir: 'libs', include: ['*.aar']) compile fileTree(dir: 'libs', include: ['*.aar'])
compile fileTree(dir: 'libs', include: ['*.jar']) compile fileTree(dir: 'libs', include: ['*.jar'])
compile project(':GlowPadBackport')
compile project(':SeekArc')
} }

View File

@ -30,6 +30,7 @@
<action android:name="android.intent.action.BOOT_COMPLETED"/> <action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter> </intent-filter>
</receiver> </receiver>
<service <service
android:name=".AlarmNotify" android:name=".AlarmNotify"
android:label="@string/alarm_notification" > android:label="@string/alarm_notification" >
@ -47,6 +48,6 @@
<!-- permission required to vibrate --> <!-- permission required to vibrate -->
<uses-permission android:name="android.permission.VIBRATE"/> <uses-permission android:name="android.permission.VIBRATE"/>
<!-- permission required to wake the device --> <!-- permission required to wake the device -->
<uses-permission android:name="android.permission.WAKE_LOCK"/> <!--uses-permission android:name="android.permission.WAKE_LOCK"/-->
</manifest> </manifest>

View File

@ -8,13 +8,13 @@ import android.content.Intent;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Vibrator;
import android.util.Log; import android.util.Log;
import android.view.View;
import android.view.Window; import android.view.Window;
import android.view.WindowManager; import android.view.WindowManager;
import android.widget.Button; import android.widget.Button;
import com.triggertrap.seekarc.SeekArc;
// TODO See GlowPad. // TODO See GlowPad.
// TODO sound audible alarm -- see AlarmKlaxon.java // TODO sound audible alarm -- see AlarmKlaxon.java
@ -22,16 +22,17 @@ import android.widget.Button;
// TODO Snooze? set another alarm for the next half-hour (or grace_period / 2)? // TODO Snooze? set another alarm for the next half-hour (or grace_period / 2)?
public class AlarmAlertActivity extends Activity { public class AlarmAlertActivity extends Activity {
// TODO correct alert lifetime
private static final int ALERT_LIFE = 1000*10; //1000*60*2; // 2 minutes
private static final long[] vPattern = {500, 500};
private static Boolean userCancelled;
private static Vibrator vibrator;
private static Intent notifyIntent; private static Intent notifyIntent;
public static Boolean alertFinished, userCancelled;
public static Activity alertActivity;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
// Self-reference so we can run finish() from outside.
alertActivity = this;
requestWindowFeature(Window.FEATURE_NO_TITLE); requestWindowFeature(Window.FEATURE_NO_TITLE);
Window window = getWindow(); Window window = getWindow();
// Set to use the full screen // Set to use the full screen
@ -47,32 +48,15 @@ public class AlarmAlertActivity extends Activity {
setContentView(R.layout.alarm_alert); setContentView(R.layout.alarm_alert);
notifyIntent = new Intent(getApplicationContext(), AlarmNotify.class); notifyIntent = new Intent(getApplicationContext(), AlarmNotify.class);
// Disable any current notifications // Disable any current notifications (if we're snoozing)
stopService(notifyIntent); stopService(notifyIntent);
// Turn off the alert activity, and switch to a notification
new Handler().postDelayed(new Runnable() {
public void run() {
// Close the dialogue and switch to notification
// if the Activity has not been closed by the user
if (!userCancelled) {
startService(notifyIntent);
finish();
}
}
}, ALERT_LIFE);
} }
@Override @Override
public void onStart() { public void onStart() {
super.onStart(); super.onStart();
userCancelled = false; /*
vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
vibrator.vibrate(vPattern, 0);
// TODO change button to slide...
// TODO change slide to circle slide? https://github.com/JesusM/HoloCircleSeekBar
Button cancelButton = (Button) findViewById(R.id.cancel_dialog_button); Button cancelButton = (Button) findViewById(R.id.cancel_dialog_button);
cancelButton.setOnClickListener (new View.OnClickListener() { cancelButton.setOnClickListener (new View.OnClickListener() {
@Override @Override
@ -80,39 +64,38 @@ public class AlarmAlertActivity extends Activity {
cancelGraceAlarm(); cancelGraceAlarm();
} }
}); });
*/
SeekArc cancelArc = (SeekArc) findViewById(R.id.cancel_dialog_seekArc);
cancelArc.setOnSeekArcChangeListener(new SeekArc.OnSeekArcChangeListener() {
volatile Boolean seekFinished = false;
@Override
public void onProgressChanged(SeekArc seekArc, int progress, boolean fromUser) {
if (progress > 98 && !seekFinished && fromUser) {
AlarmReceiver.dismissAlarm(alertActivity);
seekFinished = true;
}
}
@Override
public void onStartTrackingTouch(SeekArc seekArc) {
}
@Override
public void onStopTrackingTouch(SeekArc seekArc) {
}
});
} }
/** /**
* Handle the user pressing the back/return button * Handle the user pressing the back/return and home buttons
* TODO Do we want this to cancel the alarm and grace period?
* TODO Or do we trigger the notification and finish() right away?
* TODO probably most intuitive to cancel the alarms...
*/ */
@Override @Override
public void onBackPressed() { public void onBackPressed() {
cancelGraceAlarm(); AlarmReceiver.setAlarmStatus(AlarmReceiver.ALARM_IGNORED);
/* OR: AlarmReceiver.snoozeAlarm(this);
// Ensure that the we don't trigger the notification a second time
userCancelled = true;
startService(notifyIntent);
finish();
*/
} }
public void onStop() { public void onUserLeaveHint() {
vibrator.cancel(); AlarmReceiver.setAlarmStatus(AlarmReceiver.ALARM_IGNORED);
super.onStop(); AlarmReceiver.snoozeAlarm(this);
}
private void cancelGraceAlarm() {
AlarmManager graceManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent graceIntent = new Intent(getApplicationContext(), GraceReceiver.class);
PendingIntent gracePendingIntent = PendingIntent.getBroadcast(getApplicationContext(), MainActivity.GRACE_REQUEST, graceIntent, 0);
graceManager.cancel(gracePendingIntent);
Log.d("AlarmAlertActivity", "Cancelled grace alarm.");
// Ensure we don't load a notification now
userCancelled = true;
// Close the dialogue (stop vibration &c)
finish();
} }
} }

View File

@ -0,0 +1,130 @@
package za.org.treehouse.hypoalarm;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Vibrator;
import android.telephony.TelephonyManager;
import android.util.Log;
import java.io.IOException;
public class AlarmKlaxon {
private static final long[] vPattern = {500, 500};
// Volume modification for alarms while a phone call is active, from com.android.deskclock.alarms
private static final float IN_CALL_VOLUME = 0.125f;
private static MediaPlayer mediaPlayer = null;
private static TelephonyManager telephonyManager;
private static Vibrator vibrator;
public static void start(final Context context) {
/**
*
* TODO add raw ring tone to use as fallback
* TODO add in-call ring tone
* TODO lower volume if in a call
* TODO cancel noise if a call comes in (add TelephonyManager listener which cancels the alert but calls the notification)
*
* TODO start telephony listener
*
* TODO snooze 5 minutes on press back button or home button (new runnable)
* TODO remove back/home button and most top icons
* TODO fix glowpad/seekarc
*/
vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
vibrator.cancel();
vibrator.vibrate(vPattern, 0);
if (true)
return; // TODO remove after testing -- is mediaplayer responsible for delays?
telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
// TODO select alarm tone?
// Use the default alarm tone...
Uri alarmNoise = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
stopAudio(context);
mediaPlayer = new MediaPlayer();
mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
Log.e("AlarmAlertActivity", "Error occurred while playing audio. Stopping alarm.");
stopAudio(context);
return true;
}
});
try {
/*
* TODO find out if we're in a call
if (inTelephoneCall) {
Log.v("Using the in-call alarm");
sMediaPlayer.setVolume(IN_CALL_VOLUME, IN_CALL_VOLUME);
setDataSourceFromResource(context, sMediaPlayer, R.raw.in_call_alarm);
} else {
*/
mediaPlayer.setDataSource(context, alarmNoise);
startAudio(context);
//}
} catch (Exception ex) {
// The alarmNoise may be on the sd card which could be busy right
// now. Use the fallback ringtone.
try {
// Reset the media player to clear the error state.
mediaPlayer.reset();
//setDataSourceFromResource(this, mediaPlayer, R.raw.fallbackring);
startAudio(context);
} catch (Exception ex2) {
// At this point we just don't play anything.
Log.e("AlarmAlertActivity", "Failed to play fallback ringtone", ex2);
}
}
}
public static void stop(final Context context) {
vibrator.cancel();
if (true)
return; // TODO remove after testing
stopAudio(context);
}
private static void startAudio(final Context context) throws IOException {
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
// do not play alarms if stream volume is 0 (typically because ringer mode is silent).
if (audioManager.getStreamVolume(AudioManager.STREAM_ALARM) != 0) {
mediaPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
mediaPlayer.setLooping(true);
try {
mediaPlayer.prepare();
} catch (Exception e) {
Log.e("AlarmAlertActivity", "Prepare failed. Exiting", e);
return;
}
audioManager.requestAudioFocus(null,
AudioManager.STREAM_ALARM, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
mediaPlayer.start();
}
}
private static void stopAudio(final Context context) {
if (mediaPlayer != null) {
mediaPlayer.stop();
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
audioManager.abandonAudioFocus(null);
mediaPlayer.release();
mediaPlayer = null;
}
}
// Load ringtone from a resource
private static void setDataSourceFromResource(Context context, MediaPlayer player, int res) throws IOException {
AssetFileDescriptor afd = context.getResources().openRawResourceFd(res);
if (afd != null) {
player.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
afd.close();
}
}
}

View File

@ -27,10 +27,10 @@ public class AlarmNotify extends Service {
public void onDestroy() { public void onDestroy() {
// If the notification is cancelled, stop updating. // If the notification is cancelled, stop updating.
notificationRunning = false; notificationRunning = false;
Log.d("AlarmNotify", "1: Setting notificationRunning to false");
// Remove the notification in the notification bar // Remove the notification in the notification bar
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
nm.cancel(notifyID); nm.cancel(notifyID);
Log.d("AlarmNotify", "Notification stopped.");
} }
@Override @Override
@ -38,10 +38,10 @@ public class AlarmNotify extends Service {
final int UPDATE_INTERVAL = 10*1000; // Timer is updated six times a minute final int UPDATE_INTERVAL = 10*1000; // Timer is updated six times a minute
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
Log.d("AlarmNotify", "Notification started.");
//final String phoneNumber = sharedPref.getString(getString(R.string.PhoneNumberPref), null); //final String phoneNumber = sharedPref.getString(getString(R.string.PhoneNumberPref), null);
final int gracePeriod = sharedPref.getInt(getString(R.string.GracePeriodPref), 60); final int gracePeriod = sharedPref.getInt(getString(R.string.GracePeriodPref), 60);
// convert gracePeriod to milliseconds and calculate when it'll fire
final long endTime = System.currentTimeMillis() + (gracePeriod * 60 * 1000);
Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_grey); Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_grey);
final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
@ -55,6 +55,8 @@ public class AlarmNotify extends Service {
.setAutoCancel(false) .setAutoCancel(false)
.setPriority(Notification.PRIORITY_HIGH); .setPriority(Notification.PRIORITY_HIGH);
// TODO if alarm alert is snoozing and we cancel, cancel the snooze.
// Set up dismiss action // Set up dismiss action
Intent cancellerIntent = new Intent(getBaseContext(), CancelGraceReceiver.class); Intent cancellerIntent = new Intent(getBaseContext(), CancelGraceReceiver.class);
PendingIntent cancellerPendingIntent = PendingIntent.getBroadcast(getBaseContext(), MainActivity.CANCEL_GRACE_REQUEST, cancellerIntent, PendingIntent.FLAG_CANCEL_CURRENT); PendingIntent cancellerPendingIntent = PendingIntent.getBroadcast(getBaseContext(), MainActivity.CANCEL_GRACE_REQUEST, cancellerIntent, PendingIntent.FLAG_CANCEL_CURRENT);
@ -69,12 +71,13 @@ public class AlarmNotify extends Service {
/** /**
* TODO load alert activity (without sound or vibration) on select? * TODO load alert activity (without sound or vibration) on select?
* TODO This would allow the user to test competence * TODO This would allow the user to test competence
Intent alertActivityIntent = new Intent(this, AlarmAlertActivity.class); * something like:
alertActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent alarmAlertIntent = new Intent(this, AlarmAlertActivity.class);
Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); PendingIntent alarmPendingIntent = PendingIntent.getBroadcast(this, 0, alarmAlertIntent, 0);
notification.setContentIntent(alertActivityIntent); notification.setContentIntent(alarmPen`dingIntent);
*/ */
nm.cancel(notifyID); nm.cancel(notifyID);
nm.notify(notifyID, notification.build()); nm.notify(notifyID, notification.build());
@ -82,21 +85,22 @@ public class AlarmNotify extends Service {
@Override @Override
public void run() { public void run() {
notificationRunning = true; notificationRunning = true;
Log.d("AlarmNotify", "2: Setting notificationRunning to true");
int max = 1000; int max = 1000;
// Convert endTime from milliseconds to seconds, and translate to time remaining /* TODO check that graceEndTime is always set.
int secondsLeft = (int) ((endTime - System.currentTimeMillis())) / (1000); if (AlarmReceiver.graceEndTime == 0) {
int gracePeriodSeconds = gracePeriod * 60; AlarmReceiver.graceEndTime = System.currentTimeMillis() + (gracePeriod * 60 * 1000);
// Multiply each int by 1000 for greater progress resolution }*/
int progress = (((gracePeriodSeconds * 1000) - (secondsLeft * 1000)) * max) / (gracePeriodSeconds * 1000); // Count in milliseconds for greater progress resolution
int milliSecondsLeft = (int) ((AlarmReceiver.graceEndTime - System.currentTimeMillis()));
int gracePeriodMilliSeconds = gracePeriod * 60 * 1000;
int progress = ((gracePeriodMilliSeconds - milliSecondsLeft) * max) / gracePeriodMilliSeconds;
while (progress < max) { while (progress < max) {
// Stop the thread if cancelled elsewhere // Stop the thread if the notification is cancelled elsewhere
Log.d("AlarmNotify", "notificationRunning is " + notificationRunning);
if (!notificationRunning) { if (!notificationRunning) {
return; return;
} }
int minutesLeft = secondsLeft / 60; int minutesLeft = (milliSecondsLeft / 1000) / 60;
if (Build.VERSION.SDK_INT >= 11) { if (Build.VERSION.SDK_INT >= 11) {
notification.setContentText(String.format(getString(R.string.notificationText), MainActivity.MinutesToGracePeriodStr(minutesLeft))); notification.setContentText(String.format(getString(R.string.notificationText), MainActivity.MinutesToGracePeriodStr(minutesLeft)));
notification.setProgress(max, progress, false); notification.setProgress(max, progress, false);
@ -104,12 +108,12 @@ public class AlarmNotify extends Service {
nm.notify(notifyID, notification.build()); nm.notify(notifyID, notification.build());
} }
// Prepare secondsLeft and progress for the next loop // Prepare secondsLeft and progress for the next loop
secondsLeft = secondsLeft - (UPDATE_INTERVAL / 1000); milliSecondsLeft = milliSecondsLeft - UPDATE_INTERVAL;
// Multiply each int by 1000 for greater progress resolution // Multiply each int by 1000 for greater progress resolution
progress = (((gracePeriodSeconds * 1000) - (secondsLeft * 1000)) * max) / (gracePeriodSeconds * 1000); progress = ((gracePeriodMilliSeconds - milliSecondsLeft) * max) / gracePeriodMilliSeconds;
Log.d("AlarmNotify", "secondsLeft is " + secondsLeft + " and progress is " + progress + " (gracePeriodSeconds is " + gracePeriodSeconds + ")"); //Log.d("AlarmNotify", "milliSecondsLeft is " + milliSecondsLeft + " and progress is " + progress + " (gracePeriodMilliSeconds is " + gracePeriodMilliSeconds + ")");
// Sleeps the thread, simulating an operation
// that takes time // Sleep until we need to update again
try { try {
Thread.sleep(UPDATE_INTERVAL); Thread.sleep(UPDATE_INTERVAL);
} catch (InterruptedException e) { } catch (InterruptedException e) {

View File

@ -1,34 +1,55 @@
package za.org.treehouse.hypoalarm; package za.org.treehouse.hypoalarm;
import android.app.AlarmManager; import android.app.AlarmManager;
import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Build; import android.os.Build;
import android.os.Handler;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.util.Log; import android.util.Log;
import android.view.WindowManager; import android.widget.Toast;
import java.util.Calendar; import java.util.Calendar;
/**
* TODO change alarm state if a phone call comes in
*
* TODO display notification if alarm is about to go off (and allow user to cancel it before alarm goes off)
*
* TODO allow snooze state
*/
public class AlarmReceiver extends BroadcastReceiver { public class AlarmReceiver extends BroadcastReceiver {
private static final int SNOOZE_TIME = 1000*20; //1000*60*5; // Snooze for 5 minutes if need be
private static final int ALERT_LIFE = 1000*10; //1000*60*2; // 2 minutes
private static SharedPreferences sharedPref; private static SharedPreferences sharedPref;
private static AlarmManager alarmManager, graceManager; private static AlarmManager alarmManager, graceManager;
private static PendingIntent alarmPendingIntent, gracePendingIntent; private static PendingIntent alarmPendingIntent, gracePendingIntent;
private static Intent alertActivityIntent, notifyIntent;
public static volatile String alarmStatus; // Register ALARM_DISMISSED and its brethren here
public static final String ALARM_RUNNING = "ALARM_RUNNING";
public static final String ALARM_DISMISSED = "ALARM_DISMISSED";
public static final String ALARM_IGNORED = "ALARM_IGNORED";
public static final String ALARM_SNOOZED = "ALARM_SNOOZED";
public static final String ALARM_SNOOZE_RUNNING = "ALARM_SNOOZE_RUNNING";
public static long graceEndTime;
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(final Context context, Intent intent) {
sharedPref = PreferenceManager.getDefaultSharedPreferences(context); sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
Boolean alarmActive = sharedPref.getBoolean(context.getString(R.string.AlarmActivePref), true); Boolean alarmActive = sharedPref.getBoolean(context.getString(R.string.AlarmActivePref), true);
int gracePeriod = sharedPref.getInt(context.getString(R.string.GracePeriodPref), 60);
String alarmTimeStr = sharedPref.getString(context.getString(R.string.AlarmTimePref), null);
if (alarmActive) { if (alarmActive) {
// Set a grace period alarm to send SMS // if nothing else happens, assume the alert was ignored.
int gracePeriod = sharedPref.getInt(context.getString(R.string.GracePeriodPref), 60); alarmStatus = ALARM_RUNNING;
// Set a grace period alarm to send SMS
Calendar graceCal = Calendar.getInstance(); Calendar graceCal = Calendar.getInstance();
graceCal.set(Calendar.SECOND, 0); graceCal.set(Calendar.SECOND, 0);
graceCal.add(Calendar.MINUTE, gracePeriod); graceCal.add(Calendar.MINUTE, gracePeriod);
@ -43,16 +64,20 @@ public class AlarmReceiver extends BroadcastReceiver {
} }
Log.d("AlarmReceiver", "Setting grace alarm for " + MainActivity.debugDate(graceCal)); Log.d("AlarmReceiver", "Setting grace alarm for " + MainActivity.debugDate(graceCal));
// Allow user to acknowledge alarm and cancel grace alarm // Calculate when the grace period ends
Intent alertActivityIntent = new Intent(context, AlarmAlertActivity.class); graceEndTime = System.currentTimeMillis() + (gracePeriod * 60 * 1000);
// Set up intents for later use
notifyIntent = new Intent(context, AlarmNotify.class);
alertActivityIntent = new Intent(context, AlarmAlertActivity.class);
alertActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | alertActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
context.startActivity(alertActivityIntent);
// Allow user to acknowledge alarm and cancel grace alarm
startAlert(context);
// Reset for tomorrow; as of API 19, setRepeating() is inexact, so we use setExact() // Reset for tomorrow; as of API 19, setRepeating() is inexact, so we use setExact()
String alarmTimeStr = sharedPref.getString(context.getString(R.string.AlarmTimePref), null); // (Calendar will automatically advance the day since today's alarmTimeStr is now in the past.)
// Calendar automatically advances the day since alarmTimeStr is now in the past.
Calendar cal = MainActivity.TimeStringToCalendar(alarmTimeStr); Calendar cal = MainActivity.TimeStringToCalendar(alarmTimeStr);
alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmPendingIntent = PendingIntent.getBroadcast(context, MainActivity.ALARM_REQUEST, intent, 0); alarmPendingIntent = PendingIntent.getBroadcast(context, MainActivity.ALARM_REQUEST, intent, 0);
@ -65,4 +90,88 @@ public class AlarmReceiver extends BroadcastReceiver {
Log.d("AlarmReceiver", "Resetting alarm for " + MainActivity.debugDate(cal)); Log.d("AlarmReceiver", "Resetting alarm for " + MainActivity.debugDate(cal));
} }
} }
public static void startAlert(final Context context) {
Log.d("AlarmReceiver", "Starting alarm; status is " + alarmStatus);
// Turn off any notifications first
context.stopService(notifyIntent);
context.startActivity(alertActivityIntent);
AlarmKlaxon.start(context);
// Turn off the alert activity after a period, and switch to a notification
new Handler().postDelayed(new Runnable() {
public void run() {
// Close the dialogue and switch to notification
// if the Activity has not been closed by the user
// (that is, snoozeAlert and dismissAlert have not been called)
// TODO don't run if we've just snoozed from home/back button, but do run if
// TODO we want to finish the snooze alert activity...
if (alarmStatus.contentEquals(ALARM_DISMISSED) ||
alarmStatus.contentEquals(ALARM_SNOOZED)) {
return;
}
// Stop if we're running the snooze alert
if (alarmStatus.contentEquals(ALARM_SNOOZE_RUNNING)) {
stopAlert(context);
} else {
alarmStatus = ALARM_IGNORED; // This is true, although we are about to switch to ALARM_SNOOZED
snoozeAlarm(context);
}
}
}, ALERT_LIFE);
}
public static void stopAlert(final Context context) {
Log.d("AlarmReceiver", "Stopping alarm; status is " + alarmStatus);
AlarmKlaxon.stop(context);
AlarmAlertActivity.alertActivity.finish();
// Display a notification if the alarm hasn't been dismissed
if (!alarmStatus.contentEquals(ALARM_DISMISSED)) {
context.startService(notifyIntent);
}
}
public static void dismissAlarm(final Context context) {
Log.d("AlarmReceiver", "Dismissing alarm");
alarmStatus = ALARM_DISMISSED;
// Close the alert and all notifications
stopAlert(context);
// Cancel the graceAlarm
AlarmManager graceManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent graceIntent = new Intent(context, GraceReceiver.class);
PendingIntent gracePendingIntent = PendingIntent.getBroadcast(context, MainActivity.GRACE_REQUEST, graceIntent, 0);
graceManager.cancel(gracePendingIntent);
}
// TODO should the snooze reset the time at which the grace period alarm fires?
public static void snoozeAlarm(final Context context) {
Log.d("AlarmReceiver", "Snoozing alarm");
stopAlert(context);
// Close the alert, stop the klaxon, and start the notification,
// but only if there's time left before the gracePeriod triggers,
// and we haven't snoozed before
if (((System.currentTimeMillis() + SNOOZE_TIME) < graceEndTime) &&
(!alarmStatus.contentEquals(ALARM_SNOOZED)) &&
(!alarmStatus.contentEquals(ALARM_DISMISSED))) {
new Handler().postDelayed(new Runnable() {
public void run() {
Log.d("AlarmReceiver", "Resuming after snooze; status is " + alarmStatus);
// Don't run if the alarm was dismissed before the timer ran out
// (because a notification was acknowledged)
if (!alarmStatus.contentEquals(ALARM_DISMISSED)) {
alarmStatus = ALARM_SNOOZE_RUNNING;
startAlert(context);
}
}
}, SNOOZE_TIME);
// Change alarm status from ignored to snoozed
alarmStatus = ALARM_SNOOZED;
}
}
public static void setAlarmStatus (String status) {
Log.d("AlarmReceiver", "Setting alarm status to " + status);
alarmStatus = status;
}
} }

View File

@ -18,6 +18,9 @@ public class CancelGraceReceiver extends BroadcastReceiver {
graceManager.cancel(gracePendingIntent); graceManager.cancel(gracePendingIntent);
Log.d("CancelGraceReceiver", "Cancelled grace alarm"); Log.d("CancelGraceReceiver", "Cancelled grace alarm");
// Ensure that any snoozes that are pending never happen.
AlarmReceiver.setAlarmStatus(AlarmReceiver.ALARM_DISMISSED);
// Display toast // Display toast
Toast.makeText(context, context.getString(R.string.alarmCancelToast), Toast.LENGTH_LONG).show(); Toast.makeText(context, context.getString(R.string.alarmCancelToast), Toast.LENGTH_LONG).show();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 67 KiB

View File

@ -2,6 +2,8 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:seekarc="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".AlarmNotificationActivity"> tools:context=".AlarmNotificationActivity">
@ -9,6 +11,34 @@
<RelativeLayout <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<com.triggertrap.seekarc.SeekArc
android:id="@+id/cancel_dialog_seekArc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="100dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
seekarc:thumb="@drawable/ic_launcher"
seekarc:clockwise="false"
seekarc:rotation="0"
seekarc:startAngle="35"
seekarc:sweepAngle="295"
seekarc:arcWidth="10dp"
seekarc:progressWidth="20dp"
seekarc:roundEdges="true"
seekarc:touchInside="true" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="HypoAlarm!"
android:id="@+id/cancel_dialog_title"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_marginTop="25dp" />
<!--
<ImageView <ImageView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -36,5 +66,28 @@
android:layout_marginTop="25dp" android:layout_marginTop="25dp"
android:layout_below="@+id/cancel_dialog_title" android:layout_below="@+id/cancel_dialog_title"
android:layout_centerHorizontal="true" /> android:layout_centerHorizontal="true" />
-->
<!--
<net.sebastianopoggi.ui.GlowPadBackport.GlowPadView
android:id="@+id/incomingCallWidget"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:background="@android:color/black"
android:visibility="visible"
android:gravity="top"
app:targetDrawables="@array/incoming_call_widget_2way_targets"
app:handleDrawable="@drawable/ic_in_call_touch_handle"
app:innerRadius="@dimen/glowpadview_inner_radius"
app:outerRadius="@dimen/glowpadview_target_placement_radius"
app:outerRingDrawable="@drawable/ic_lockscreen_outerring"
app:snapMargin="@dimen/glowpadview_snap_margin"
app:vibrationDuration="20"
app:feedbackCount="1"
app:glowRadius="@dimen/glowpadview_glow_radius"
app:pointDrawable="@drawable/ic_lockscreen_glowdot"/>
-->
</RelativeLayout> </RelativeLayout>
</FrameLayout> </FrameLayout>

View File

@ -3,4 +3,30 @@
<!-- Default screen margins, per the Android Design guidelines. --> <!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen> <dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen> <dimen name="activity_vertical_margin">16dp</dimen>
<!-- Default target placement radius for GlowPadView. Should be 1/2 of outerring diameter. -->
<dimen name="glowpadview_target_placement_radius">135dip</dimen>
<!-- Default glow radius for GlowPadView -->
<dimen name="glowpadview_glow_radius">75dip</dimen>
<!-- Default distance beyond which GlowPadView snaps to the matching target -->
<dimen name="glowpadview_snap_margin">40dip</dimen>
<!-- Default distance from each snap target that GlowPadView considers a "hit" -->
<dimen name="glowpadview_inner_radius">15dip</dimen>
<!-- Size of lockscreen outerring on unsecure unlock LockScreen -->
<dimen name="keyguard_lockscreen_outerring_diameter">270dp</dimen>
<!-- Circle size for incoming call widget's each item. -->
<dimen name="incoming_call_widget_circle_size">94dp</dimen>
<!-- Margin used for incoming call widget's icon for each item.
This should be same as "(incoming_call_widget_circle_size - icon_size)/2".
Right now answer/decline/reject icons have 38dp width/height.
So, (94 - 38)/2 ==> 28dp -->
<dimen name="incoming_call_widget_asset_margin">28dp</dimen>
</resources> </resources>

View File

@ -57,4 +57,11 @@
<string name="alarmCancelled">All HypoAlarms cancelled</string> <string name="alarmCancelled">All HypoAlarms cancelled</string>
<array name="incoming_call_widget_2way_targets">
<item>@drawable/ic_lockscreen_answer</item>
<item>@null</item>
<item>@drawable/ic_lockscreen_decline</item>
<item>@null</item>"
</array>
</resources> </resources>

View File

@ -5,4 +5,13 @@
<!-- Customize your theme here. --> <!-- Customize your theme here. -->
</style> </style>
<style name="SeekArc">
<item name="arcColor">@color/progress_gray_dark</item>
</style>
<style name="SeekArcLight">
<item name="arcColor">@color/progress_gray</item>
</style>
</resources> </resources>

76
SeekArc/SeekArc.iml Normal file
View File

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="HypoAlarm" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle">
<configuration>
<option name="GRADLE_PROJECT_PATH" value=":SeekArc" />
</configuration>
</facet>
<facet type="android" name="Android">
<configuration>
<option name="SELECTED_BUILD_VARIANT" value="debug" />
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugJava" />
<option name="ASSEMBLE_TEST_TASK_NAME" value="assembleDebugTest" />
<option name="SOURCE_GEN_TASK_NAME" value="generateDebugSources" />
<option name="ALLOW_USER_CONFIGURATION" value="false" />
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
<option name="LIBRARY_PROJECT" value="true" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/build/classes/debug" />
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/build/source/r/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/source/aidl/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/source/buildConfig/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/source/rs/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/res/rs/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/source/r/test/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/source/aidl/test/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/source/buildConfig/test/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/source/rs/test/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/res/rs/test/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build/apk" />
<excludeFolder url="file://$MODULE_DIR$/build/assets" />
<excludeFolder url="file://$MODULE_DIR$/build/bundles" />
<excludeFolder url="file://$MODULE_DIR$/build/classes" />
<excludeFolder url="file://$MODULE_DIR$/build/dependency-cache" />
<excludeFolder url="file://$MODULE_DIR$/build/incremental" />
<excludeFolder url="file://$MODULE_DIR$/build/libs" />
<excludeFolder url="file://$MODULE_DIR$/build/manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/res" />
<excludeFolder url="file://$MODULE_DIR$/build/symbols" />
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
</content>
<orderEntry type="jdk" jdkName="Android API 19 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

19
SeekArc/build.gradle Normal file
View File

@ -0,0 +1,19 @@
apply plugin: 'android-library'
android {
compileSdkVersion 19
buildToolsVersion "19.0.1"
defaultConfig {
minSdkVersion 8
targetSdkVersion 17
versionCode 1
versionName "1.0"
}
buildTypes {
release {
runProguard false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
}

View File

@ -0,0 +1,13 @@
/**
* Automatically generated file. DO NOT MODIFY
*/
package com.triggertrap.seekarc;
public final class BuildConfig {
public static final boolean DEBUG = Boolean.parseBoolean("true");
public static final String PACKAGE_NAME = "com.triggertrap.seekarc";
public static final String BUILD_TYPE = "debug";
public static final String FLAVOR = "";
public static final int VERSION_CODE = 1;
public static final String VERSION_NAME = "1.0";
}

View File

@ -0,0 +1,13 @@
/**
* Automatically generated file. DO NOT MODIFY
*/
package com.triggertrap.seekarc;
public final class BuildConfig {
public static final boolean DEBUG = false;
public static final String PACKAGE_NAME = "com.triggertrap.seekarc";
public static final String BUILD_TYPE = "release";
public static final String FLAVOR = "";
public static final int VERSION_CODE = 1;
public static final String VERSION_NAME = "1.0";
}

View File

@ -0,0 +1,419 @@
/* AUTO-GENERATED FILE. DO NOT MODIFY.
*
* This class was automatically generated by the
* aapt tool from the resource data it found. It
* should not be modified by hand.
*/
package com.triggertrap.seekarc;
public final class R {
public static final class attr {
/** <p>Must be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",
"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
*/
public static int arcColor=0x7f010009;
/** <p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".
Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),
in (inches), mm (millimeters).
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
*/
public static int arcWidth=0x7f010004;
/** <p>Must be a boolean value, either "<code>true</code>" or "<code>false</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
*/
public static int clockwise=0x7f01000d;
/** <p>Must be an integer value, such as "<code>100</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
*/
public static int max=0x7f010002;
/** <p>Must be an integer value, such as "<code>100</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
*/
public static int progress=0x7f010005;
/** <p>Must be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",
"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
*/
public static int progressColor=0x7f01000a;
/** <p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".
Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),
in (inches), mm (millimeters).
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
*/
public static int progressWidth=0x7f010003;
/** <p>Must be an integer value, such as "<code>100</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
*/
public static int rotation=0x7f010006;
/** <p>Must be a boolean value, either "<code>true</code>" or "<code>false</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
*/
public static int roundEdges=0x7f01000b;
/** <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"
or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".
*/
public static int seekArcStyle=0x7f01000e;
/** <p>Must be an integer value, such as "<code>100</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
*/
public static int startAngle=0x7f010007;
/** <p>Must be an integer value, such as "<code>100</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
*/
public static int sweepAngle=0x7f010008;
/** <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"
or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".
*/
public static int thumb=0x7f010000;
/** <p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".
Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),
in (inches), mm (millimeters).
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
*/
public static int thumbOffset=0x7f010001;
/** <p>Must be a boolean value, either "<code>true</code>" or "<code>false</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
*/
public static int touchInside=0x7f01000c;
}
public static final class color {
public static int progress_gray=0x7f030000;
public static int progress_gray_dark=0x7f030001;
}
public static final class drawable {
public static int ic_launcher=0x7f020000;
public static int scrubber_control_disabled_holo=0x7f020001;
public static int scrubber_control_focused_holo=0x7f020002;
public static int scrubber_control_normal_holo=0x7f020003;
public static int scrubber_control_pressed_holo=0x7f020004;
public static int seek_arc_control_selector=0x7f020005;
}
public static final class string {
public static int app_name=0x7f040000;
}
public static final class style {
public static int SeekArc=0x7f050000;
public static int SeekArcLight=0x7f050001;
}
public static final class styleable {
/** Attributes that can be used with a SeekArc.
<p>Includes the following attributes:</p>
<table>
<colgroup align="left" />
<colgroup align="left" />
<tr><th>Attribute</th><th>Description</th></tr>
<tr><td><code>{@link #SeekArc_arcColor com.triggertrap.seekarc:arcColor}</code></td><td></td></tr>
<tr><td><code>{@link #SeekArc_arcWidth com.triggertrap.seekarc:arcWidth}</code></td><td></td></tr>
<tr><td><code>{@link #SeekArc_clockwise com.triggertrap.seekarc:clockwise}</code></td><td></td></tr>
<tr><td><code>{@link #SeekArc_max com.triggertrap.seekarc:max}</code></td><td></td></tr>
<tr><td><code>{@link #SeekArc_progress com.triggertrap.seekarc:progress}</code></td><td></td></tr>
<tr><td><code>{@link #SeekArc_progressColor com.triggertrap.seekarc:progressColor}</code></td><td></td></tr>
<tr><td><code>{@link #SeekArc_progressWidth com.triggertrap.seekarc:progressWidth}</code></td><td></td></tr>
<tr><td><code>{@link #SeekArc_rotation com.triggertrap.seekarc:rotation}</code></td><td></td></tr>
<tr><td><code>{@link #SeekArc_roundEdges com.triggertrap.seekarc:roundEdges}</code></td><td></td></tr>
<tr><td><code>{@link #SeekArc_startAngle com.triggertrap.seekarc:startAngle}</code></td><td></td></tr>
<tr><td><code>{@link #SeekArc_sweepAngle com.triggertrap.seekarc:sweepAngle}</code></td><td></td></tr>
<tr><td><code>{@link #SeekArc_thumb com.triggertrap.seekarc:thumb}</code></td><td></td></tr>
<tr><td><code>{@link #SeekArc_thumbOffset com.triggertrap.seekarc:thumbOffset}</code></td><td></td></tr>
<tr><td><code>{@link #SeekArc_touchInside com.triggertrap.seekarc:touchInside}</code></td><td></td></tr>
</table>
@see #SeekArc_arcColor
@see #SeekArc_arcWidth
@see #SeekArc_clockwise
@see #SeekArc_max
@see #SeekArc_progress
@see #SeekArc_progressColor
@see #SeekArc_progressWidth
@see #SeekArc_rotation
@see #SeekArc_roundEdges
@see #SeekArc_startAngle
@see #SeekArc_sweepAngle
@see #SeekArc_thumb
@see #SeekArc_thumbOffset
@see #SeekArc_touchInside
*/
public static final int[] SeekArc = {
0x7f010000, 0x7f010001, 0x7f010002, 0x7f010003,
0x7f010004, 0x7f010005, 0x7f010006, 0x7f010007,
0x7f010008, 0x7f010009, 0x7f01000a, 0x7f01000b,
0x7f01000c, 0x7f01000d
};
/**
<p>This symbol is the offset where the {@link com.triggertrap.seekarc.R.attr#arcColor}
attribute's value can be found in the {@link #SeekArc} array.
<p>Must be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",
"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
@attr name com.triggertrap.seekarc:arcColor
*/
public static final int SeekArc_arcColor = 9;
/**
<p>This symbol is the offset where the {@link com.triggertrap.seekarc.R.attr#arcWidth}
attribute's value can be found in the {@link #SeekArc} array.
<p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".
Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),
in (inches), mm (millimeters).
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
@attr name com.triggertrap.seekarc:arcWidth
*/
public static final int SeekArc_arcWidth = 4;
/**
<p>This symbol is the offset where the {@link com.triggertrap.seekarc.R.attr#clockwise}
attribute's value can be found in the {@link #SeekArc} array.
<p>Must be a boolean value, either "<code>true</code>" or "<code>false</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
@attr name com.triggertrap.seekarc:clockwise
*/
public static final int SeekArc_clockwise = 13;
/**
<p>This symbol is the offset where the {@link com.triggertrap.seekarc.R.attr#max}
attribute's value can be found in the {@link #SeekArc} array.
<p>Must be an integer value, such as "<code>100</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
@attr name com.triggertrap.seekarc:max
*/
public static final int SeekArc_max = 2;
/**
<p>This symbol is the offset where the {@link com.triggertrap.seekarc.R.attr#progress}
attribute's value can be found in the {@link #SeekArc} array.
<p>Must be an integer value, such as "<code>100</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
@attr name com.triggertrap.seekarc:progress
*/
public static final int SeekArc_progress = 5;
/**
<p>This symbol is the offset where the {@link com.triggertrap.seekarc.R.attr#progressColor}
attribute's value can be found in the {@link #SeekArc} array.
<p>Must be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",
"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
@attr name com.triggertrap.seekarc:progressColor
*/
public static final int SeekArc_progressColor = 10;
/**
<p>This symbol is the offset where the {@link com.triggertrap.seekarc.R.attr#progressWidth}
attribute's value can be found in the {@link #SeekArc} array.
<p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".
Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),
in (inches), mm (millimeters).
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
@attr name com.triggertrap.seekarc:progressWidth
*/
public static final int SeekArc_progressWidth = 3;
/**
<p>This symbol is the offset where the {@link com.triggertrap.seekarc.R.attr#rotation}
attribute's value can be found in the {@link #SeekArc} array.
<p>Must be an integer value, such as "<code>100</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
@attr name com.triggertrap.seekarc:rotation
*/
public static final int SeekArc_rotation = 6;
/**
<p>This symbol is the offset where the {@link com.triggertrap.seekarc.R.attr#roundEdges}
attribute's value can be found in the {@link #SeekArc} array.
<p>Must be a boolean value, either "<code>true</code>" or "<code>false</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
@attr name com.triggertrap.seekarc:roundEdges
*/
public static final int SeekArc_roundEdges = 11;
/**
<p>This symbol is the offset where the {@link com.triggertrap.seekarc.R.attr#startAngle}
attribute's value can be found in the {@link #SeekArc} array.
<p>Must be an integer value, such as "<code>100</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
@attr name com.triggertrap.seekarc:startAngle
*/
public static final int SeekArc_startAngle = 7;
/**
<p>This symbol is the offset where the {@link com.triggertrap.seekarc.R.attr#sweepAngle}
attribute's value can be found in the {@link #SeekArc} array.
<p>Must be an integer value, such as "<code>100</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
@attr name com.triggertrap.seekarc:sweepAngle
*/
public static final int SeekArc_sweepAngle = 8;
/**
<p>This symbol is the offset where the {@link com.triggertrap.seekarc.R.attr#thumb}
attribute's value can be found in the {@link #SeekArc} array.
<p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"
or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".
@attr name com.triggertrap.seekarc:thumb
*/
public static final int SeekArc_thumb = 0;
/**
<p>This symbol is the offset where the {@link com.triggertrap.seekarc.R.attr#thumbOffset}
attribute's value can be found in the {@link #SeekArc} array.
<p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".
Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),
in (inches), mm (millimeters).
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
@attr name com.triggertrap.seekarc:thumbOffset
*/
public static final int SeekArc_thumbOffset = 1;
/**
<p>This symbol is the offset where the {@link com.triggertrap.seekarc.R.attr#touchInside}
attribute's value can be found in the {@link #SeekArc} array.
<p>Must be a boolean value, either "<code>true</code>" or "<code>false</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
@attr name com.triggertrap.seekarc:touchInside
*/
public static final int SeekArc_touchInside = 12;
/** Attributes that can be used with a SeekArcTheme.
<p>Includes the following attributes:</p>
<table>
<colgroup align="left" />
<colgroup align="left" />
<tr><th>Attribute</th><th>Description</th></tr>
<tr><td><code>{@link #SeekArcTheme_seekArcStyle com.triggertrap.seekarc:seekArcStyle}</code></td><td></td></tr>
</table>
@see #SeekArcTheme_seekArcStyle
*/
public static final int[] SeekArcTheme = {
0x7f01000e
};
/**
<p>This symbol is the offset where the {@link com.triggertrap.seekarc.R.attr#seekArcStyle}
attribute's value can be found in the {@link #SeekArcTheme} array.
<p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"
or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".
@attr name com.triggertrap.seekarc:seekArcStyle
*/
public static final int SeekArcTheme_seekArcStyle = 0;
};
}

View File

@ -0,0 +1,418 @@
/* AUTO-GENERATED FILE. DO NOT MODIFY.
*
* This class was automatically generated by the
* aapt tool from the resource data it found. It
* should not be modified by hand.
*/
package com.triggertrap.seekarc;
public final class R {
public static final class attr {
/** <p>Must be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",
"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
*/
public static int arcColor=0x7f010009;
/** <p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".
Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),
in (inches), mm (millimeters).
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
*/
public static int arcWidth=0x7f010004;
/** <p>Must be a boolean value, either "<code>true</code>" or "<code>false</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
*/
public static int clockwise=0x7f01000d;
/** <p>Must be an integer value, such as "<code>100</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
*/
public static int max=0x7f010002;
/** <p>Must be an integer value, such as "<code>100</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
*/
public static int progress=0x7f010005;
/** <p>Must be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",
"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
*/
public static int progressColor=0x7f01000a;
/** <p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".
Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),
in (inches), mm (millimeters).
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
*/
public static int progressWidth=0x7f010003;
/** <p>Must be an integer value, such as "<code>100</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
*/
public static int rotation=0x7f010006;
/** <p>Must be a boolean value, either "<code>true</code>" or "<code>false</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
*/
public static int roundEdges=0x7f01000b;
/** <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"
or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".
*/
public static int seekArcStyle=0x7f01000e;
/** <p>Must be an integer value, such as "<code>100</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
*/
public static int startAngle=0x7f010007;
/** <p>Must be an integer value, such as "<code>100</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
*/
public static int sweepAngle=0x7f010008;
/** <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"
or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".
*/
public static int thumb=0x7f010000;
/** <p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".
Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),
in (inches), mm (millimeters).
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
*/
public static int thumbOffset=0x7f010001;
/** <p>Must be a boolean value, either "<code>true</code>" or "<code>false</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
*/
public static int touchInside=0x7f01000c;
}
public static final class color {
public static int progress_gray=0x7f030000;
public static int progress_gray_dark=0x7f030001;
}
public static final class drawable {
public static int scrubber_control_disabled_holo=0x7f020000;
public static int scrubber_control_focused_holo=0x7f020001;
public static int scrubber_control_normal_holo=0x7f020002;
public static int scrubber_control_pressed_holo=0x7f020003;
public static int seek_arc_control_selector=0x7f020004;
}
public static final class string {
public static int app_name=0x7f040000;
}
public static final class style {
public static int SeekArc=0x7f050000;
public static int SeekArcLight=0x7f050001;
}
public static final class styleable {
/** Attributes that can be used with a SeekArc.
<p>Includes the following attributes:</p>
<table>
<colgroup align="left" />
<colgroup align="left" />
<tr><th>Attribute</th><th>Description</th></tr>
<tr><td><code>{@link #SeekArc_arcColor com.triggertrap.seekarc:arcColor}</code></td><td></td></tr>
<tr><td><code>{@link #SeekArc_arcWidth com.triggertrap.seekarc:arcWidth}</code></td><td></td></tr>
<tr><td><code>{@link #SeekArc_clockwise com.triggertrap.seekarc:clockwise}</code></td><td></td></tr>
<tr><td><code>{@link #SeekArc_max com.triggertrap.seekarc:max}</code></td><td></td></tr>
<tr><td><code>{@link #SeekArc_progress com.triggertrap.seekarc:progress}</code></td><td></td></tr>
<tr><td><code>{@link #SeekArc_progressColor com.triggertrap.seekarc:progressColor}</code></td><td></td></tr>
<tr><td><code>{@link #SeekArc_progressWidth com.triggertrap.seekarc:progressWidth}</code></td><td></td></tr>
<tr><td><code>{@link #SeekArc_rotation com.triggertrap.seekarc:rotation}</code></td><td></td></tr>
<tr><td><code>{@link #SeekArc_roundEdges com.triggertrap.seekarc:roundEdges}</code></td><td></td></tr>
<tr><td><code>{@link #SeekArc_startAngle com.triggertrap.seekarc:startAngle}</code></td><td></td></tr>
<tr><td><code>{@link #SeekArc_sweepAngle com.triggertrap.seekarc:sweepAngle}</code></td><td></td></tr>
<tr><td><code>{@link #SeekArc_thumb com.triggertrap.seekarc:thumb}</code></td><td></td></tr>
<tr><td><code>{@link #SeekArc_thumbOffset com.triggertrap.seekarc:thumbOffset}</code></td><td></td></tr>
<tr><td><code>{@link #SeekArc_touchInside com.triggertrap.seekarc:touchInside}</code></td><td></td></tr>
</table>
@see #SeekArc_arcColor
@see #SeekArc_arcWidth
@see #SeekArc_clockwise
@see #SeekArc_max
@see #SeekArc_progress
@see #SeekArc_progressColor
@see #SeekArc_progressWidth
@see #SeekArc_rotation
@see #SeekArc_roundEdges
@see #SeekArc_startAngle
@see #SeekArc_sweepAngle
@see #SeekArc_thumb
@see #SeekArc_thumbOffset
@see #SeekArc_touchInside
*/
public static final int[] SeekArc = {
0x7f010000, 0x7f010001, 0x7f010002, 0x7f010003,
0x7f010004, 0x7f010005, 0x7f010006, 0x7f010007,
0x7f010008, 0x7f010009, 0x7f01000a, 0x7f01000b,
0x7f01000c, 0x7f01000d
};
/**
<p>This symbol is the offset where the {@link com.triggertrap.seekarc.R.attr#arcColor}
attribute's value can be found in the {@link #SeekArc} array.
<p>Must be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",
"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
@attr name com.triggertrap.seekarc:arcColor
*/
public static final int SeekArc_arcColor = 9;
/**
<p>This symbol is the offset where the {@link com.triggertrap.seekarc.R.attr#arcWidth}
attribute's value can be found in the {@link #SeekArc} array.
<p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".
Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),
in (inches), mm (millimeters).
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
@attr name com.triggertrap.seekarc:arcWidth
*/
public static final int SeekArc_arcWidth = 4;
/**
<p>This symbol is the offset where the {@link com.triggertrap.seekarc.R.attr#clockwise}
attribute's value can be found in the {@link #SeekArc} array.
<p>Must be a boolean value, either "<code>true</code>" or "<code>false</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
@attr name com.triggertrap.seekarc:clockwise
*/
public static final int SeekArc_clockwise = 13;
/**
<p>This symbol is the offset where the {@link com.triggertrap.seekarc.R.attr#max}
attribute's value can be found in the {@link #SeekArc} array.
<p>Must be an integer value, such as "<code>100</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
@attr name com.triggertrap.seekarc:max
*/
public static final int SeekArc_max = 2;
/**
<p>This symbol is the offset where the {@link com.triggertrap.seekarc.R.attr#progress}
attribute's value can be found in the {@link #SeekArc} array.
<p>Must be an integer value, such as "<code>100</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
@attr name com.triggertrap.seekarc:progress
*/
public static final int SeekArc_progress = 5;
/**
<p>This symbol is the offset where the {@link com.triggertrap.seekarc.R.attr#progressColor}
attribute's value can be found in the {@link #SeekArc} array.
<p>Must be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",
"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
@attr name com.triggertrap.seekarc:progressColor
*/
public static final int SeekArc_progressColor = 10;
/**
<p>This symbol is the offset where the {@link com.triggertrap.seekarc.R.attr#progressWidth}
attribute's value can be found in the {@link #SeekArc} array.
<p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".
Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),
in (inches), mm (millimeters).
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
@attr name com.triggertrap.seekarc:progressWidth
*/
public static final int SeekArc_progressWidth = 3;
/**
<p>This symbol is the offset where the {@link com.triggertrap.seekarc.R.attr#rotation}
attribute's value can be found in the {@link #SeekArc} array.
<p>Must be an integer value, such as "<code>100</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
@attr name com.triggertrap.seekarc:rotation
*/
public static final int SeekArc_rotation = 6;
/**
<p>This symbol is the offset where the {@link com.triggertrap.seekarc.R.attr#roundEdges}
attribute's value can be found in the {@link #SeekArc} array.
<p>Must be a boolean value, either "<code>true</code>" or "<code>false</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
@attr name com.triggertrap.seekarc:roundEdges
*/
public static final int SeekArc_roundEdges = 11;
/**
<p>This symbol is the offset where the {@link com.triggertrap.seekarc.R.attr#startAngle}
attribute's value can be found in the {@link #SeekArc} array.
<p>Must be an integer value, such as "<code>100</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
@attr name com.triggertrap.seekarc:startAngle
*/
public static final int SeekArc_startAngle = 7;
/**
<p>This symbol is the offset where the {@link com.triggertrap.seekarc.R.attr#sweepAngle}
attribute's value can be found in the {@link #SeekArc} array.
<p>Must be an integer value, such as "<code>100</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
@attr name com.triggertrap.seekarc:sweepAngle
*/
public static final int SeekArc_sweepAngle = 8;
/**
<p>This symbol is the offset where the {@link com.triggertrap.seekarc.R.attr#thumb}
attribute's value can be found in the {@link #SeekArc} array.
<p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"
or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".
@attr name com.triggertrap.seekarc:thumb
*/
public static final int SeekArc_thumb = 0;
/**
<p>This symbol is the offset where the {@link com.triggertrap.seekarc.R.attr#thumbOffset}
attribute's value can be found in the {@link #SeekArc} array.
<p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".
Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),
in (inches), mm (millimeters).
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
@attr name com.triggertrap.seekarc:thumbOffset
*/
public static final int SeekArc_thumbOffset = 1;
/**
<p>This symbol is the offset where the {@link com.triggertrap.seekarc.R.attr#touchInside}
attribute's value can be found in the {@link #SeekArc} array.
<p>Must be a boolean value, either "<code>true</code>" or "<code>false</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
@attr name com.triggertrap.seekarc:touchInside
*/
public static final int SeekArc_touchInside = 12;
/** Attributes that can be used with a SeekArcTheme.
<p>Includes the following attributes:</p>
<table>
<colgroup align="left" />
<colgroup align="left" />
<tr><th>Attribute</th><th>Description</th></tr>
<tr><td><code>{@link #SeekArcTheme_seekArcStyle com.triggertrap.seekarc:seekArcStyle}</code></td><td></td></tr>
</table>
@see #SeekArcTheme_seekArcStyle
*/
public static final int[] SeekArcTheme = {
0x7f01000e
};
/**
<p>This symbol is the offset where the {@link com.triggertrap.seekarc.R.attr#seekArcStyle}
attribute's value can be found in the {@link #SeekArcTheme} array.
<p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"
or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".
@attr name com.triggertrap.seekarc:seekArcStyle
*/
public static final int SeekArcTheme_seekArcStyle = 0;
};
}

Binary file not shown.

21
SeekArc/licence.txt Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2013 Triggertrap Ltd
Author Neil Davies
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,20 @@
# To enable ProGuard in your project, edit project.properties
# to define the proguard.config property as described in that file.
#
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in ${sdk.dir}/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the ProGuard
# include property in project.properties.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

View File

@ -0,0 +1,15 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system edit
# "ant.properties", and override values to adapt the script to your
# project structure.
#
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target.
target=android-17
android.library=true

View File

@ -0,0 +1,39 @@
<!--
The MIT License (MIT)
Copyright (c) 2013 Triggertrap Ltd
Author Neil Davies
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.triggertrap.seekarc"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<application
android:allowBackup="true"
android:label="@string/app_name"
>
</application>
</manifest>

View File

@ -0,0 +1,528 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2013 Triggertrap Ltd
* Author Neil Davies
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************/
package com.triggertrap.seekarc;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
/**
*
* SeekArc.java
*
* This is a class that functions much like a SeekBar but
* follows a circle path instead of a straight line.
*
* @author Neil Davies
*
*/
public class SeekArc extends View {
private static final String TAG = SeekArc.class.getSimpleName();
private static int INVALID_PROGRESS_VALUE = -1;
// The initial rotational offset -90 means we start at 12 o'clock
private final int mAngleOffset = -90;
/**
* The Drawable for the seek arc thumbnail
*/
private Drawable mThumb;
/**
* The Maximum value that this SeekArc can be set to
*/
private int mMax = 100;
/**
* The Current value that the SeekArc is set to
*/
private int mProgress = 0;
/**
* The width of the progress line for this SeekArc
*/
private int mProgressWidth = 4;
/**
* The Width of the background arc for the SeekArc
*/
private int mArcWidth = 2;
/**
* The Angle to start drawing this Arc from
*/
private int mStartAngle = 0;
/**
* The Angle through which to draw the arc (Max is 360)
*/
private int mSweepAngle = 360;
/**
* The rotation of the SeekArc- 0 is twelve o'clock
*/
private int mRotation = 0;
/**
* Give the SeekArc rounded edges
*/
private boolean mRoundedEdges = false;
/**
* Enable touch inside the SeekArc
*/
private boolean mTouchInside = true;
/**
* Will the progress increase clockwise or anti-clockwise
*/
private boolean mClockwise = true;
// Internal variables
private int mArcRadius = 0;
private float mProgressSweep = 0;
private RectF mArcRect = new RectF();
private Paint mArcPaint;
private Paint mProgressPaint;
private int mTranslateX;
private int mTranslateY;
private int mThumbXPos;
private int mThumbYPos;
private double mTouchAngle;
private float mTouchIgnoreRadius;
private OnSeekArcChangeListener mOnSeekArcChangeListener;
public interface OnSeekArcChangeListener {
/**
* Notification that the progress level has changed. Clients can use the
* fromUser parameter to distinguish user-initiated changes from those
* that occurred programmatically.
*
* @param seekArc
* The SeekArc whose progress has changed
* @param progress
* The current progress level. This will be in the range
* 0..max where max was set by
* {@link ProgressArc#setMax(int)}. (The default value for
* max is 100.)
* @param fromUser
* True if the progress change was initiated by the user.
*/
void onProgressChanged(SeekArc seekArc, int progress, boolean fromUser);
/**
* Notification that the user has started a touch gesture. Clients may
* want to use this to disable advancing the seekbar.
*
* @param seekArc
* The SeekArc in which the touch gesture began
*/
void onStartTrackingTouch(SeekArc seekArc);
/**
* Notification that the user has finished a touch gesture. Clients may
* want to use this to re-enable advancing the seekarc.
*
* @param seekArc
* The SeekArc in which the touch gesture began
*/
void onStopTrackingTouch(SeekArc seekArc);
}
public SeekArc(Context context) {
super(context);
init(context, null, 0);
}
public SeekArc(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, R.attr.seekArcStyle);
}
public SeekArc(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs, defStyle);
}
private void init(Context context, AttributeSet attrs, int defStyle) {
Log.d(TAG, "Initialising SeekArc");
final Resources res = getResources();
float density = context.getResources().getDisplayMetrics().density;
// Defaults, may need to link this into theme settings
int arcColor = res.getColor(R.color.progress_gray);
int progressColor = res.getColor(android.R.color.holo_blue_light);
int thumbHalfheight = 0;
int thumbHalfWidth = 0;
mThumb = res.getDrawable(R.drawable.seek_arc_control_selector);
// Convert progress width to pixels for current density
mProgressWidth = (int) (mProgressWidth * density);
if (attrs != null) {
// Attribute initialization
final TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.SeekArc, defStyle, 0);
Drawable thumb = a.getDrawable(R.styleable.SeekArc_thumb);
if (thumb != null) {
mThumb = thumb;
}
thumbHalfheight = (int) mThumb.getIntrinsicHeight() / 2;
thumbHalfWidth = (int) mThumb.getIntrinsicWidth() / 2;
mThumb.setBounds(-thumbHalfWidth, -thumbHalfheight, thumbHalfWidth,
thumbHalfheight);
mMax = a.getInteger(R.styleable.SeekArc_max, mMax);
mProgress = a.getInteger(R.styleable.SeekArc_progress, mProgress);
mProgressWidth = (int) a.getDimension(
R.styleable.SeekArc_progressWidth, mProgressWidth);
mArcWidth = (int) a.getDimension(R.styleable.SeekArc_arcWidth,
mArcWidth);
mStartAngle = a.getInt(R.styleable.SeekArc_startAngle, mStartAngle);
mSweepAngle = a.getInt(R.styleable.SeekArc_sweepAngle, mSweepAngle);
mRotation = a.getInt(R.styleable.SeekArc_rotation, mRotation);
mRoundedEdges = a.getBoolean(R.styleable.SeekArc_roundEdges,
mRoundedEdges);
mTouchInside = a.getBoolean(R.styleable.SeekArc_touchInside,
mTouchInside);
mClockwise = a.getBoolean(R.styleable.SeekArc_clockwise,
mClockwise);
arcColor = a.getColor(R.styleable.SeekArc_arcColor, arcColor);
progressColor = a.getColor(R.styleable.SeekArc_progressColor,
progressColor);
a.recycle();
}
mProgress = (mProgress > mMax) ? mMax : mProgress;
mProgress = (mProgress < 0) ? 0 : mProgress;
mSweepAngle = (mSweepAngle > 360) ? 360 : mSweepAngle;
mSweepAngle = (mSweepAngle < 0) ? 0 : mSweepAngle;
mStartAngle = (mStartAngle > 360) ? 0 : mStartAngle;
mStartAngle = (mStartAngle < 0) ? 0 : mStartAngle;
mArcPaint = new Paint();
mArcPaint.setColor(arcColor);
mArcPaint.setAntiAlias(true);
mArcPaint.setStyle(Paint.Style.STROKE);
mArcPaint.setStrokeWidth(mArcWidth);
//mArcPaint.setAlpha(45);
mProgressPaint = new Paint();
mProgressPaint.setColor(progressColor);
mProgressPaint.setAntiAlias(true);
mProgressPaint.setStyle(Paint.Style.STROKE);
mProgressPaint.setStrokeWidth(mProgressWidth);
if (mRoundedEdges) {
mArcPaint.setStrokeCap(Paint.Cap.ROUND);
mProgressPaint.setStrokeCap(Paint.Cap.ROUND);
}
}
@Override
protected void onDraw(Canvas canvas) {
if(!mClockwise) {
canvas.scale(-1, 1, mArcRect.centerX(), mArcRect.centerY() );
}
// Draw the arcs
final int arcStart = mStartAngle + mAngleOffset + mRotation;
final int arcSweep = mSweepAngle;
canvas.drawArc(mArcRect, arcStart, arcSweep, false, mArcPaint);
canvas.drawArc(mArcRect, arcStart, mProgressSweep, false,
mProgressPaint);
// Draw the thumb nail
canvas.translate(mTranslateX -mThumbXPos, mTranslateY -mThumbYPos);
mThumb.draw(canvas);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int height = getDefaultSize(getSuggestedMinimumHeight(),
heightMeasureSpec);
final int width = getDefaultSize(getSuggestedMinimumWidth(),
widthMeasureSpec);
final int min = Math.min(width, height);
float top = 0;
float left = 0;
int arcDiameter = 0;
mTranslateX = (int) (width * 0.5f);
mTranslateY = (int) (height * 0.5f);
arcDiameter = min - getPaddingLeft();
mArcRadius = arcDiameter / 2;
top = height / 2 - (arcDiameter / 2);
left = width / 2 - (arcDiameter / 2);
mArcRect.set(left, top, left + arcDiameter, top + arcDiameter);
int arcStart = (int)mProgressSweep + mStartAngle + mRotation + 90;
mThumbXPos = (int) (mArcRadius * Math.cos(Math.toRadians(arcStart)));
mThumbYPos = (int) (mArcRadius * Math.sin(Math.toRadians(arcStart)));
setTouchInSide(mTouchInside);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
onStartTrackingTouch();
updateOnTouch(event);
break;
case MotionEvent.ACTION_MOVE:
updateOnTouch(event);
break;
case MotionEvent.ACTION_UP:
onStopTrackingTouch();
setPressed(false);
break;
case MotionEvent.ACTION_CANCEL:
onStopTrackingTouch();
setPressed(false);
break;
}
return true;
}
@Override
protected void drawableStateChanged() {
super.drawableStateChanged();
if (mThumb != null && mThumb.isStateful()) {
int[] state = getDrawableState();
mThumb.setState(state);
}
invalidate();
}
private void onStartTrackingTouch() {
if (mOnSeekArcChangeListener != null) {
mOnSeekArcChangeListener.onStartTrackingTouch(this);
}
}
private void onStopTrackingTouch() {
if (mOnSeekArcChangeListener != null) {
mOnSeekArcChangeListener.onStopTrackingTouch(this);
}
}
private void updateOnTouch(MotionEvent event) {
boolean ignoreTouch = ignoreTouch(event.getX(), event.getY());
if (ignoreTouch) {
return;
}
setPressed(true);
mTouchAngle = getTouchDegrees(event.getX(), event.getY());
int progress = getProgressForAngle(mTouchAngle);
onProgressRefresh(progress, true);
}
private boolean ignoreTouch(float xPos, float yPos) {
boolean ignore = false;
float x = xPos - mTranslateX;
float y = yPos - mTranslateY;
float touchRadius = (float) Math.sqrt(((x * x) + (y * y)));
if (touchRadius < mTouchIgnoreRadius) {
ignore = true;
}
return ignore;
}
private double getTouchDegrees(float xPos, float yPos) {
float x = xPos - mTranslateX;
float y = yPos - mTranslateY;
//invert the x-coord if we are rotating anti-clockwise
x= (mClockwise) ? x:-x;
// convert to arc Angle
double angle = Math.toDegrees(Math.atan2(y, x) + (Math.PI / 2)
- Math.toRadians(mRotation));
if (angle < 0) {
angle = 360 + angle;
}
angle -= mStartAngle;
return angle;
}
private int getProgressForAngle(double angle) {
int touchProgress = (int) Math.round(valuePerDegree() * angle);
touchProgress = (touchProgress < 0) ? INVALID_PROGRESS_VALUE
: touchProgress;
touchProgress = (touchProgress > mMax) ? INVALID_PROGRESS_VALUE
: touchProgress;
return touchProgress;
}
private float valuePerDegree() {
return (float) mMax / mSweepAngle;
}
private void onProgressRefresh(int progress, boolean fromUser) {
updateProgress(progress, fromUser);
}
private void updateThumbPosition() {
int thumbAngle = (int) (mStartAngle + mProgressSweep + mRotation + 90);
mThumbXPos = (int) (mArcRadius * Math.cos(Math.toRadians(thumbAngle)));
mThumbYPos = (int) (mArcRadius * Math.sin(Math.toRadians(thumbAngle)));
}
private void updateProgress(int progress, boolean fromUser) {
if (progress == INVALID_PROGRESS_VALUE) {
return;
}
if (mOnSeekArcChangeListener != null) {
mOnSeekArcChangeListener
.onProgressChanged(this, progress, fromUser);
}
progress = (progress > mMax) ? mMax : progress;
progress = (mProgress < 0) ? 0 : progress;
mProgress = progress;
mProgressSweep = (float) progress / mMax * mSweepAngle;
updateThumbPosition();
invalidate();
}
/**
* Sets a listener to receive notifications of changes to the SeekArc's
* progress level. Also provides notifications of when the user starts and
* stops a touch gesture within the SeekArc.
*
* @param l
* The seek bar notification listener
*
* @see SeekArc.OnSeekBarChangeListener
*/
public void setOnSeekArcChangeListener(OnSeekArcChangeListener l) {
mOnSeekArcChangeListener = l;
}
public void setProgress(int progress) {
updateProgress(progress, false);
}
public int getProgressWidth() {
return mProgressWidth;
}
public void setProgressWidth(int mProgressWidth) {
this.mProgressWidth = mProgressWidth;
mProgressPaint.setStrokeWidth(mProgressWidth);
}
public int getArcWidth() {
return mArcWidth;
}
public void setArcWidth(int mArcWidth) {
this.mArcWidth = mArcWidth;
mArcPaint.setStrokeWidth(mArcWidth);
}
public int getArcRotation() {
return mRotation;
}
public void setArcRotation(int mRotation) {
this.mRotation = mRotation;
updateThumbPosition();
}
public int getStartAngle() {
return mStartAngle;
}
public void setStartAngle(int mStartAngle) {
this.mStartAngle = mStartAngle;
updateThumbPosition();
}
public int getSweepAngle() {
return mSweepAngle;
}
public void setSweepAngle(int mSweepAngle) {
this.mSweepAngle = mSweepAngle;
updateThumbPosition();
}
public void setRoundedEdges(boolean isEnabled) {
mRoundedEdges = isEnabled;
if (mRoundedEdges) {
mArcPaint.setStrokeCap(Paint.Cap.ROUND);
mProgressPaint.setStrokeCap(Paint.Cap.ROUND);
} else {
mArcPaint.setStrokeCap(Paint.Cap.SQUARE);
mProgressPaint.setStrokeCap(Paint.Cap.SQUARE);
}
}
public void setTouchInSide(boolean isEnabled) {
int thumbHalfheight = (int) mThumb.getIntrinsicHeight() / 2;
int thumbHalfWidth = (int) mThumb.getIntrinsicWidth() / 2;
mTouchInside = isEnabled;
if (mTouchInside) {
mTouchIgnoreRadius = (float) mArcRadius / 4;
} else {
// Don't use the exact radius makes interaction too tricky
mTouchIgnoreRadius = mArcRadius
- Math.min(thumbHalfWidth, thumbHalfheight);
}
}
public void setClockwise(boolean isClockwise) {
mClockwise = isClockwise;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -0,0 +1,31 @@
<!--
The MIT License (MIT)
Copyright (c) 2013 Triggertrap Ltd
Author Neil Davies
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/scrubber_control_disabled_holo" android:state_enabled="false"/>
<item android:drawable="@drawable/scrubber_control_pressed_holo" android:state_pressed="true"/>
<item android:drawable="@drawable/scrubber_control_focused_holo" android:state_selected="true"/>
<item android:drawable="@drawable/scrubber_control_normal_holo"/>
</selector>

View File

@ -0,0 +1,47 @@
<!--
The MIT License (MIT)
Copyright (c) 2013 Triggertrap Ltd
Author Neil Davies
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-->
<resources>
<declare-styleable name="SeekArc">
<attr name="thumb" format="reference" />
<attr name="thumbOffset" format="dimension" />
<attr name="max" format="integer" />
<attr name="progressWidth" format="dimension" />
<attr name="arcWidth" format="dimension" />
<attr name="progress" format="integer" />
<attr name="rotation" format="integer" />
<attr name="startAngle" format="integer" />
<attr name="sweepAngle" format="integer" />
<attr name="arcColor" format="color" />
<attr name="progressColor" format="color" />
<attr name="roundEdges" format="boolean" />
<attr name="touchInside" format="boolean" />
<attr name="clockwise" format="boolean" />
</declare-styleable>
<declare-styleable name="SeekArcTheme">
<attr name="seekArcStyle" format="reference"></attr>
</declare-styleable>
</resources>

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
The MIT License (MIT)
Copyright (c) 2013 Triggertrap Ltd
Author Neil Davies
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-->
<resources>
<color name="progress_gray">#FFD8D8D8</color>
<color name="progress_gray_dark">#FF383838</color>
</resources>

View File

@ -0,0 +1,28 @@
<!--
The MIT License (MIT)
Copyright (c) 2013 Triggertrap Ltd
Author Neil Davies
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-->
<resources>
<string name="app_name">Seekarc_library</string>
</resources>

View File

@ -0,0 +1,34 @@
<!--
The MIT License (MIT)
Copyright (c) 2013 Triggertrap Ltd
Author Neil Davies
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-->
<resources>
<style name="SeekArc">
<item name="arcColor">@color/progress_gray_dark</item>
</style>
<style name="SeekArcLight">
<item name="arcColor">@color/progress_gray</item>
</style>
</resources>

View File

@ -1 +1 @@
include ':HypoAlarm', ':GlowPadBackport' include ':HypoAlarm', ':GlowPadBackport', ':SeekArc'