summaryrefslogtreecommitdiffstats
path: root/src/net/hoopajoo/android/SoftKeys/SoftKeysService.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/net/hoopajoo/android/SoftKeys/SoftKeysService.java')
-rw-r--r--src/net/hoopajoo/android/SoftKeys/SoftKeysService.java440
1 files changed, 440 insertions, 0 deletions
diff --git a/src/net/hoopajoo/android/SoftKeys/SoftKeysService.java b/src/net/hoopajoo/android/SoftKeys/SoftKeysService.java
new file mode 100644
index 0000000..0de7e42
--- /dev/null
+++ b/src/net/hoopajoo/android/SoftKeys/SoftKeysService.java
@@ -0,0 +1,440 @@
+/*
+ *
+ * Copyright (c) 2010 Steve Slaven
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+*/
+package net.hoopajoo.android.SoftKeys;
+
+import android.app.Service;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.graphics.PixelFormat;
+import android.hardware.SensorManager;
+import android.os.IBinder;
+import android.preference.PreferenceManager;
+import android.util.Log;
+import android.view.Display;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.OrientationEventListener;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.View.OnClickListener;
+import android.view.View.OnLongClickListener;
+import android.view.View.OnTouchListener;
+import android.view.animation.AlphaAnimation;
+import android.view.animation.Animation;
+import android.view.animation.LayoutAnimationController;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+
+public class SoftKeysService extends Service {
+ private View mView;
+ private View mBumpView;
+ private boolean auto_hide;
+ private boolean auto_hide_after_back;
+ private boolean mDraggingView;
+ private int mDraggingOrigX, mDraggingOrigY;
+ private int mDraggingViewX, mDraggingViewY;
+ private boolean mDidDrag;
+ private int mNumDrags;
+ private OrientationEventListener mOrientation;
+
+ private final int mOffScreenMax = 20;
+
+ private int mScreenWidth;
+ private int mScreenHeight;
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+
+ OnClickListener c = new OnClickListener() {
+ @Override
+ public void onClick( View v ) {
+ // send an intent to the main window
+ Intent i = null;
+ boolean hide = auto_hide;
+ switch( v.getId() ) {
+ case R.id.home:
+ i = new Intent( Keys.ACTION_HOME );
+ break;
+
+ case R.id.back:
+ i = new Intent( Keys.ACTION_BACK );
+ if( hide ) {
+ hide = auto_hide_after_back;
+ }
+ break;
+
+ case R.id.menu:
+ i = new Intent( Keys.ACTION_MENU );
+ break;
+
+ case R.id.search:
+ i = new Intent( Keys.ACTION_SEARCH );
+ break;
+
+ case R.id.exit:
+ hide = true;
+ break;
+ }
+
+ if( i != null ) {
+ i.addFlags( Intent.FLAG_ACTIVITY_NEW_TASK );
+ i.setClass( v.getContext(), Keys.class );
+ v.getContext().startActivity( i );
+ }
+
+ if( hide ) {
+ toggle_bar();
+ }
+ }
+ };
+
+ OnLongClickListener longpress = new OnLongClickListener() {
+ @Override
+ public boolean onLongClick( View v ) {
+ if( mDraggingView || mDidDrag ) {
+ return false;
+ }
+
+ // rotate
+ LinearLayout l = (LinearLayout)mView.findViewById( R.id.button_container );
+ if( l.getOrientation() == LinearLayout.HORIZONTAL ) {
+ l.setOrientation( LinearLayout.VERTICAL );
+ }else{
+ l.setOrientation( LinearLayout.HORIZONTAL );
+ }
+
+ savePosition();
+ return true;
+ }
+ };
+
+ OnTouchListener touch = new OnTouchListener() {
+ @Override
+ public boolean onTouch(View view, MotionEvent me) {
+ if (me.getAction() == MotionEvent.ACTION_DOWN) {
+ mDraggingOrigX = (int)me.getRawX();
+ mDraggingOrigY = (int)me.getRawY();
+
+ View root = view.getRootView();
+ WindowManager.LayoutParams l = (WindowManager.LayoutParams)root.getLayoutParams();
+ mDraggingViewX = l.x;
+ mDraggingViewY = l.y;
+
+ // If we're anchored use orig x/y as the main loc
+ if( l.gravity != (Gravity.TOP | Gravity.LEFT) ) {
+ int[] loc = new int[ 2 ];
+ root.getLocationOnScreen( loc );
+ mDraggingViewX = loc[ 0 ];
+ mDraggingViewY = loc[ 1 ];
+ }
+
+ mDraggingView = false;
+ mDidDrag = false;
+ mNumDrags = 0;
+ }
+ if (me.getAction() == MotionEvent.ACTION_UP) {
+ mDraggingView = false;
+
+ if( mDidDrag ) {
+ // save x/y
+ savePosition();
+
+ // do not click
+ return( true );
+ }
+ } else if (me.getAction() == MotionEvent.ACTION_MOVE) {
+ mNumDrags++; // only really start dragging after a few drag events, so when
+ // you're just tapping buttons it doesn't drag too by accident
+
+ if( mNumDrags > 2 ) {
+ mDraggingView = true;
+ mDidDrag = true;
+
+ int currX = (int)me.getRawX();
+ int currY = (int)me.getRawY();
+
+ // make our deltas work relative to movement, y
+ int dx = currX - mDraggingOrigX;
+ int dy = currY - mDraggingOrigY;
+
+ //d( "dx: " + dx );
+ //d( "dy: " + dy );
+
+
+ View root = view.getRootView();
+ WindowManager.LayoutParams l = (WindowManager.LayoutParams)root.getLayoutParams();
+ //d( "x: " + l.x );
+ //d( "y: " + l.y );
+ //d( "grav: " + l.gravity );
+ int width = root.getWidth();
+ int height = root.getHeight();
+
+ //l.gravity = Gravity.NO_GRAVITY;
+ //l.gravity = Gravity.TOP | Gravity.LEFT;
+ //l.x += dx;
+ //l.y += dy;
+
+ l.x = mDraggingViewX + dx;
+ l.y = mDraggingViewY + dy;
+
+ // contraints
+ if( l.x < ( mOffScreenMax * -1 ) ) {
+ l.x = mOffScreenMax * -1;
+ }
+
+ if( l.x + width > mScreenWidth + mOffScreenMax ) {
+ l.x = mScreenWidth + mOffScreenMax - width;
+ }
+
+ if( l.y < ( mOffScreenMax * -1 ) ) {
+ l.y = mOffScreenMax * -1;
+ }
+
+ if( l.y + height > mScreenHeight + mOffScreenMax ) {
+ l.y = mScreenHeight + mOffScreenMax - height;
+ }
+
+ WindowManager wm = (WindowManager)getSystemService(WINDOW_SERVICE);
+ wm.updateViewLayout( root, l );
+ return( true );
+ }
+ }
+ return false;
+ }
+ };
+
+ // get our root (don't go through theme handler, this comes from the main app always)
+ LayoutInflater l = LayoutInflater.from( this );
+ mView = l.inflate( R.layout.service, null );
+
+ mOrientation = new OrientationEventListener( this, SensorManager.SENSOR_DELAY_NORMAL ) {
+ @Override
+ public void onOrientationChanged( int orientation ) {
+ initOrientation();
+ }
+ };
+ mOrientation.enable();
+
+ SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences( this );
+
+ // set back/auto hide stuff
+ auto_hide = settings.getBoolean( "service_close_after", true );
+ auto_hide_after_back = settings.getBoolean( "service_close_after_back", false );
+
+ // get button sizes
+ String size = settings.getString( "service_size", "medium" );
+ float buttonMult = 1;
+ if( size.equals( "huge" ) ) {
+ buttonMult = 2;
+ }else if( size.equals( "large" ) ) {
+ buttonMult = 1.5f;
+ }else if( size.equals( "medium" ) ) {
+ // regular size for the system
+ buttonMult = 1;
+ }else if( size.equals( "small" ) ) {
+ buttonMult = 0.75f;
+ }else if( size.equals( "tiny" ) ) {
+ buttonMult = 0.5f;
+ }
+
+ // insert the container
+ ViewGroup container = (ViewGroup)Generator.createButtonContainer( this, 0, buttonMult, "service", (ViewGroup)mView.findViewById( R.id.main_view ) );
+ container.removeView( container.findViewById( R.id.settings ) ); // no settings in service
+
+ // arrange buttons
+ Keys.applyButtons( settings, mView, c, longpress, touch, true );
+ mView.setVisibility( View.INVISIBLE );
+ mView.setOnTouchListener( touch );
+ mView.setOnLongClickListener( longpress );
+
+ applyTransparency( mView, settings.getInt( "service_transparency", 0 ) );
+
+ if( settings.getBoolean( "service_no_background", false ) ) {
+ // make button container transparent
+ ((LinearLayout)mView.findViewById( R.id.button_container )).setBackgroundResource( 0 );
+ ((LinearLayout)mView.findViewById( R.id.button_container )).setPadding( 0, 0, 0, 0 );
+ }
+
+ // Put together the popper
+ mBumpView = l.inflate( R.layout.service_popper, null );
+ mBumpView.setOnTouchListener( touch );
+
+ // insert the button
+ Generator.createButtonContainer( this, 0, buttonMult, "service_popper",
+ (ViewGroup)mBumpView.findViewById( R.id.main_view ),
+ new int[] { R.id.popper } );
+
+ ImageButton b = (ImageButton)mBumpView.findViewById( R.id.popper );
+ b.setOnTouchListener( touch );
+
+ // apply alpha
+ applyTransparency( mBumpView, settings.getInt( "service_popper_transparency", 0 ) );
+
+ b.setOnClickListener( new OnClickListener() {
+ @Override
+ public void onClick( View v ) {
+ toggle_bar();
+ }
+ } );
+
+ WindowManager wm = (WindowManager)getSystemService(WINDOW_SERVICE);
+ wm.addView( mBumpView, makeOverlayParams() );
+ wm.addView( mView, makeOverlayParams() );
+
+ initOrientation();
+ }
+
+ private WindowManager.LayoutParams makeOverlayParams() {
+ return new WindowManager.LayoutParams(
+ WindowManager.LayoutParams.WRAP_CONTENT,
+ WindowManager.LayoutParams.WRAP_CONTENT,
+ WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
+ // in adjustWindowParams system overlay windows are stripped of focus/touch events
+ //WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
+ WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL|
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+ PixelFormat.TRANSLUCENT);
+ }
+
+ public void initOrientation() {
+ // init x/y of buttons and save screen width/heigth
+ SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences( this );
+ WindowManager wm = (WindowManager)getSystemService(WINDOW_SERVICE);
+
+ // save screen width/height
+ Display display = wm.getDefaultDisplay();
+ mScreenWidth = display.getWidth();
+ mScreenHeight = display.getHeight();
+
+ /*
+ // popup button
+ //params.gravity = Gravity.RIGHT;
+ WindowManager.LayoutParams params = (WindowManager.LayoutParams)mBumpView.getLayoutParams();
+ params.x = settings.getInt( "service_bump_last_x", 0 );
+ params.y = settings.getInt( "service_bump_last_y", 0 );
+ if( params.x == 0 && params.y == 0 ) {
+ params.gravity = Gravity.RIGHT;
+ }else{
+ params.gravity = Gravity.TOP | Gravity.LEFT;
+ }
+ wm.updateViewLayout(mBumpView, params);
+
+ params = (WindowManager.LayoutParams)mView.getLayoutParams();
+ params.x = settings.getInt( "service_last_x", 0 );
+ params.y = settings.getInt( "service_last_y", 0 );
+ if( params.x == 0 && params.y == 0 ) {
+ params.gravity = Gravity.CENTER | Gravity.BOTTOM;
+ }else{
+ params.gravity = Gravity.TOP | Gravity.LEFT;
+ }
+
+ wm.updateViewLayout(mView, params);
+ */
+
+ // popup button
+ //params.gravity = Gravity.RIGHT;
+ WindowManager.LayoutParams params = (WindowManager.LayoutParams)mBumpView.getLayoutParams();
+ params.x = settings.getInt( "service_bump_last_x", 0 );
+ params.y = settings.getInt( "service_bump_last_y", 0 );
+ params.gravity = Gravity.TOP | Gravity.LEFT;
+ if( params.x == 0 && params.y == 0 ) {
+ // float right by default
+ params.x = mScreenWidth - mBumpView.getWidth();
+ params.y = ( mScreenHeight / 2 ) - mBumpView.getHeight();
+ }
+ wm.updateViewLayout(mBumpView, params);
+
+ params = (WindowManager.LayoutParams)mView.getLayoutParams();
+ params.x = settings.getInt( "service_last_x", 0 );
+ params.y = settings.getInt( "service_last_y", 0 );
+ params.gravity = Gravity.TOP | Gravity.LEFT;
+ if( params.x == 0 && params.y == 0 ) {
+ // bottom center
+ params.x = ( mScreenWidth - mView.getWidth() ) / 2;
+ params.y = ( mScreenHeight - mView.getHeight() ) - 30;
+ }
+
+ wm.updateViewLayout(mView, params);
+
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ // remove our views
+ WindowManager wm = (WindowManager)getSystemService(WINDOW_SERVICE);
+ wm.removeView( mView );
+ wm.removeView( mBumpView );
+
+ mView = null;
+ mBumpView = null;
+
+ mOrientation.disable();
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ private void d( String msg ) {
+ Log.d( "SoftKeysService", msg );
+ }
+
+ public void toggle_bar() {
+ if( mView.getVisibility() == View.INVISIBLE ) {
+ mView.setVisibility( View.VISIBLE );
+ }else{
+ mView.setVisibility( View.INVISIBLE );
+ }
+ }
+
+ private void savePosition() {
+ SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences( this );
+
+ SharedPreferences.Editor e = settings.edit();
+ WindowManager.LayoutParams l = (WindowManager.LayoutParams)mView.getLayoutParams();
+ e.putInt( "service_last_x", l.x );
+ e.putInt( "service_last_y", l.y );
+
+ l = (WindowManager.LayoutParams)mBumpView.getLayoutParams();
+ e.putInt( "service_bump_last_x", l.x );
+ e.putInt( "service_bump_last_y", l.y );
+
+ e.putInt( "service_last_orientation",
+ ((LinearLayout)mView.findViewById( R.id.button_container )).getOrientation() );
+ e.commit();
+ }
+
+ private void applyTransparency( View v, int amount ) {
+ // apply transparency, is there a better way?
+ float transparency = (float)amount;
+ float finalAlpha = ( 100f - transparency ) / 100f;
+
+ Animation alpha = new AlphaAnimation( finalAlpha, finalAlpha );
+ alpha.setDuration( 0 );
+ alpha.setFillAfter( true );
+
+ // need to create an animation controller since its empty by default and the animation doesn't work
+ ((ViewGroup)v).setLayoutAnimation( new LayoutAnimationController( alpha, 0 ) );
+ }
+}