/*
* Copyright (C) 2014 The AppCan Open Source Project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.zywx.wbpalmstar.platform.myspace;
import org.zywx.wbpalmstar.base.ResoureFinder;
import android.app.Activity;
import android.app.Service;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.Vibrator;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.Window;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
public class GSenseView extends View implements SensorEventListener {
public static final String TAG = "GSenseView";
private static final int GSENSE_MIN_VELOCITY = 300;
private Bitmap bitmapBall;
private Bitmap bitmapHole;
private int bitmapW;
private int bitmapH;
public static float left;
public static float top;
private float radius;
public static int viewWith;
public static int viewHeight;
private int maxLeft;
private int maxTop;
private float dissAreaLeft;
private float dissAreaTop;
private float dissAreaRight;
private float dissAreaBottom;
private Paint paint = new Paint();
private Activity activity;
public int windowHeight;
public int windowWidth;
private Vibrator mVibrator;
private SensorManager sm;
private long mLastTime;
public static float ballXVelocity;
public static float ballYVelocity;
private WindowManager.LayoutParams params;
private OnBallFallIntoCallback sensorCallback;
private SoundPool soundPool;
private int soundId;
private ResoureFinder finder;
public GSenseView(Context context) {
super(context);
init();
}
public GSenseView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public void addBallFallIntoCallback(OnBallFallIntoCallback callback) {
this.sensorCallback = callback;
}
private void init() {
finder = ResoureFinder.getInstance(getContext());
soundPool = new SoundPool(1, AudioManager.STREAM_MUSIC, 0);
soundId = soundPool.load(getContext(), finder.getRawId("collision"), 1);
touchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
DisplayMetrics dm = getResources().getDisplayMetrics();
bitmapBall = BitmapFactory.decodeResource(getResources(), finder.getDrawableId("platform_myspace_ball"));
bitmapHole = BitmapFactory.decodeResource(getResources(), finder.getDrawableId("platform_myspace_hole"));
bitmapW = bitmapBall.getWidth();
bitmapH = bitmapBall.getHeight();
radius = bitmapW / 2;
dissAreaLeft = 200 * dm.density;
dissAreaTop = 50 * dm.density;
dissAreaRight = dissAreaLeft + bitmapHole.getWidth();
dissAreaBottom = dissAreaTop + bitmapHole.getHeight();
activity = (Activity) getContext();
Rect rectgle = new Rect();
Window window = activity.getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
windowWidth = rectgle.width();
windowHeight = rectgle.height();
mVibrator = (Vibrator) activity.getApplication().getSystemService(Service.VIBRATOR_SERVICE);
sm = (SensorManager) activity.getSystemService(Context.SENSOR_SERVICE);
setBackgroundDrawable(finder.getDrawable("platform_myspace_gsense_bg_shape"));
params = new WindowManager.LayoutParams();
params.height = windowHeight;
params.width = windowWidth;
params.type = WindowManager.LayoutParams.TYPE_APPLICATION | WindowManager.LayoutParams.FIRST_SUB_WINDOW;
params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_BLUR_BEHIND;// 模态,不能获得焦点,背景失焦
params.alpha = 1.0f;
params.format = PixelFormat.TRANSPARENT;
params.gravity = Gravity.LEFT | Gravity.TOP;
params.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
params.x = dm.widthPixels - windowWidth;
params.y = dm.heightPixels - windowHeight;
params.windowAnimations = finder.getStyleId("Anim_platform_myspace_fade");
}
public LayoutParams getLayoutParams() {
return params;
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
viewWith = w;
viewHeight = h;
maxLeft = viewWith - bitmapW;
maxTop = viewHeight - bitmapH;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (left < 0.0f) {
if (Math.abs(ballXVelocity) > GSENSE_MIN_VELOCITY) {
soundPool.play(soundId, 1.0f, 1.0f, 0, 1, 1.0f);
}
left = 0.0f;
ballXVelocity = -(ballXVelocity / 1.4f);
} else if (left > maxLeft) {
if (Math.abs(ballXVelocity) > GSENSE_MIN_VELOCITY) {
soundPool.play(soundId, 1.0f, 1.0f, 0, 1, 1.0f);
}
left = maxLeft;
ballXVelocity = -(ballXVelocity / 1.4f);
}
if (top < 0.0f) {
if (Math.abs(ballYVelocity) > GSENSE_MIN_VELOCITY) {
soundPool.play(soundId, 1.0f, 1.0f, 0, 1, 1.0f);
}
top = 0.0f;
ballYVelocity = -(ballYVelocity / 1.4f);
} else if (top > maxTop) {
if (Math.abs(ballYVelocity) > GSENSE_MIN_VELOCITY) {
soundPool.play(soundId, 1.0f, 1.0f, 0, 1, 1.0f);
}
top = maxTop;
ballYVelocity = -(ballYVelocity / 1.4f);
}
canvas.drawBitmap(bitmapHole, dissAreaLeft, dissAreaTop, paint);
canvas.drawBitmap(bitmapBall, left, top, paint);
float ballX = left + radius;
float ballY = top + radius;
float xRange = (dissAreaRight - dissAreaLeft) / 3f;
float yRange = (dissAreaBottom - dissAreaTop) / 3f;
if (ballX >= dissAreaLeft + xRange && ballX <= dissAreaRight - xRange && ballY >= dissAreaTop + yRange
&& ballY <= dissAreaBottom - yRange) {
mVibrator.vibrate(500);
performSenseAction();
}
}
public void startSense() {
mLastTime = 0;
ballXVelocity = 0.0f;
ballYVelocity = 0.0f;
sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_GAME);
}
public void stopSense() {
sm.unregisterListener(this);
mLastTime = 0;
ballXVelocity = 0.0f;
ballYVelocity = 0.0f;
}
private float startX;
private float startY;
private int touchSlop;
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = event.getX();
startY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
if (Math.abs(event.getX() - startX) > touchSlop || Math.abs(event.getY() - startY) > touchSlop) {
return false;
}
break;
case MotionEvent.ACTION_UP:
if ((Math.abs(event.getX() - startX) < touchSlop && Math.abs(event.getY() - startY) < touchSlop)) {
performSenseAction();
}
break;
}
return super.onTouchEvent(event);
}
private void performSenseAction() {
if (sensorCallback != null) {
stopSense();
sensorCallback.onFallInto();
left = 0.0f;
top = 0.0f;
}
}
@Override
public void onSensorChanged(SensorEvent event) {
long now = System.currentTimeMillis();
{
long diff = 0;
if (mLastTime != 0)
diff = now - mLastTime;
if (Math.abs(event.values[SensorManager.DATA_X]) > 1.5f) { //
if (Math.abs(event.values[SensorManager.DATA_X]) < 10.0f)
diff = 1;
if (mLastTime != 0)
ballXVelocity = ballXVelocity + (-event.values[SensorManager.DATA_X] * diff * 20);
} else {
ballXVelocity = ballXVelocity + (event.values[SensorManager.DATA_X]); //
}
if (Math.abs(event.values[SensorManager.DATA_Y]) > 1.5f) { //
if (Math.abs(event.values[SensorManager.DATA_Y]) < 10.0f)
diff = 1;
if (mLastTime != 0)
ballYVelocity = ballYVelocity + (event.values[SensorManager.DATA_Y] * diff * 10);
} else {
ballYVelocity = ballYVelocity + (-event.values[SensorManager.DATA_Y]);
}
mLastTime = now;
left += ballXVelocity / 200;
top += ballYVelocity / 200;
invalidate();
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
public void startVibrate() {
mVibrator.vibrate(new long[]{100, 100, 100, 1000}, -1);
}
public void cancelVibrate() {
mVibrator.cancel();
}
public static interface OnBallFallIntoCallback {
void onFallInto();
}
}