diff options
-rw-r--r-- | AndroidManifest.xml | 8 | ||||
-rw-r--r-- | res/values/strings.xml | 18 | ||||
-rw-r--r-- | res/xml/prefs.xml | 35 | ||||
-rw-r--r-- | src/net/hoopajoo/android/SoftKeys/BootReceiver.java | 36 | ||||
-rw-r--r-- | src/net/hoopajoo/android/SoftKeys/Globals.java | 193 | ||||
-rw-r--r-- | src/net/hoopajoo/android/SoftKeys/Keys.java | 136 | ||||
-rw-r--r-- | src/net/hoopajoo/android/SoftKeys/SoftKeysService.java | 17 |
7 files changed, 283 insertions, 160 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 7307a44..0d6be4b 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -66,7 +66,13 @@ </intent-filter> --> </activity> - + + <receiver android:name=".BootReceiver"> + <intent-filter> + <action android:name ="android.intent.action.BOOT_COMPLETED"/> + </intent-filter> + </receiver> + <service android:name=".SoftKeysService"/> </application> <uses-sdk android:minSdkVersion="4" /> diff --git a/res/values/strings.xml b/res/values/strings.xml index dfea6a7..d1421a4 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -14,6 +14,24 @@ <string name="pref_service_title">Run Service</string> <string name="pref_service_summary_on">Run SoftKeys Service</string> <string name="pref_service_summary_off">Just Use SoftKeys Launcher</string> + + <string name="pref_service_boot_title">Run Service at Boot</string> + <string name="pref_service_boot_summary_on">Run SoftKeys Service at Boot (even if not default launcher)</string> + <string name="pref_service_boot_summary_off">Do Not Run SoftKeys Service at Boot (only if not default launcher)</string> + + <string name="pref_service_drag_title">Draggable Service</string> + <string name="pref_service_drag_summary_on">Allow Dragging Service Buttons</string> + <string name="pref_service_drag_summary_off">Service Buttons Do Not mMve</string> + + <string name="pref_service_drag_popper_title">Draggable Popper</string> + <string name="pref_service_drag_popper_summary_on">Allow Dragging Popper Button</string> + <string name="pref_service_drag_popper_summary_off">Popper Button Does Not Move</string> + + <string name="pref_service_drag_extra_title">Draggable D-Pad</string> + <string name="pref_service_drag_extra_summary_on">Allow Dragging D-Pad Buttons</string> + <string name="pref_service_drag_extra_summary_off">D-Pad Buttons Do Not Move</string> + + <string name="pref_service_size_title">Size</string> <string name="pref_service_size_summary">Size of Service Popup Buttons</string> <string name="pref_service_transparency_title">Button Bar Transparency</string> diff --git a/res/xml/prefs.xml b/res/xml/prefs.xml index fddc692..f2bfd5b 100644 --- a/res/xml/prefs.xml +++ b/res/xml/prefs.xml @@ -30,6 +30,14 @@ android:key="service" /> + <CheckBoxPreference + android:title="@string/pref_service_boot_title" + android:summaryOn="@string/pref_service_boot_summary_on" + android:summaryOff="@string/pref_service_boot_summary_off" + android:defaultValue="true" + android:key="service_boot" + /> + <ListPreference android:title="@string/pref_service_size_title" android:summaryOn="@string/pref_service_size_summary" @@ -38,6 +46,30 @@ android:defaultValue="medium" android:key="service_size" /> + + <CheckBoxPreference + android:title="@string/pref_service_drag_popper_title" + android:summaryOn="@string/pref_service_drag_popper_summary_on" + android:summaryOff="@string/pref_service_drag_popper_summary_off" + android:defaultValue="true" + android:key="service_drag_popper" + /> + + <CheckBoxPreference + android:title="@string/pref_service_drag_title" + android:summaryOn="@string/pref_service_drag_summary_on" + android:summaryOff="@string/pref_service_drag_summary_off" + android:defaultValue="true" + android:key="service_drag" + /> + + <CheckBoxPreference + android:title="@string/pref_service_drag_extra_title" + android:summaryOn="@string/pref_service_drag_extra_summary_on" + android:summaryOff="@string/pref_service_drag_extra_summary_off" + android:defaultValue="true" + android:key="service_drag_extra" + /> <com.hlidskialf.android.preference.SeekBarPreference android:key="service_transparency" @@ -61,7 +93,8 @@ android:summary="@string/pref_service_popper_transparency_summary" android:defaultValue="0" android:max="100" - /> + /> + <CheckBoxPreference android:title="@string/pref_service_close_after_title" android:summaryOn="@string/pref_service_close_after_summary_on" diff --git a/src/net/hoopajoo/android/SoftKeys/BootReceiver.java b/src/net/hoopajoo/android/SoftKeys/BootReceiver.java new file mode 100644 index 0000000..bdf4a1a --- /dev/null +++ b/src/net/hoopajoo/android/SoftKeys/BootReceiver.java @@ -0,0 +1,36 @@ +/* + * + * 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.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; + +public class BootReceiver extends BroadcastReceiver { + @Override + public void onReceive( Context c, Intent i ) { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences( c ); + if( prefs.getBoolean( "service_boot", true ) ) { + c.startService( new Intent( c, SoftKeysService.class ) ); + //((Globals)c).bootup(); + } + } +} diff --git a/src/net/hoopajoo/android/SoftKeys/Globals.java b/src/net/hoopajoo/android/SoftKeys/Globals.java index 31d3f95..992805b 100644 --- a/src/net/hoopajoo/android/SoftKeys/Globals.java +++ b/src/net/hoopajoo/android/SoftKeys/Globals.java @@ -27,14 +27,21 @@ import java.util.Iterator; import java.util.List; import android.app.Application; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.AssetManager; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; import android.preference.PreferenceManager; import android.provider.Settings; import android.util.Log; +import android.widget.RemoteViews; import android.widget.Toast; public class Globals extends Application { @@ -42,11 +49,42 @@ public class Globals extends Application { private String android_id = null; private String LOG = "SoftKeys.Global"; + private boolean mBooted = false; public boolean restartKeys = false; public int homeCounter = 0; public boolean didInitNotifications = false; public boolean firstRun = true; + // simple typedef used to make the notifications a bit more generic + private class NotificationButton { + String mPrefKey; + RemoteViews mView; + int mIconId; + Drawable mIcon; + String mButtonText; + String mAction; + String mExtraString; + + NotificationButton( String text, String pref, RemoteViews view, Drawable d, int icon, String act, String extra ) { + mButtonText = text; + mPrefKey = pref; + mView = view; + mIconId = icon; + mIcon = d; + mAction = act; + mExtraString = extra; + } + + NotificationButton( String text, String pref, RemoteViews view, Drawable d, int icon, String act ) { + this( text, pref, view, d, icon, act, null ); + } + + NotificationButton( String text, String pref, int icon, String act ) { + this( text, pref, null, null, icon, act, null ); + } + + } + // interface to root context class public RootContext getRootContext() throws Exception { if( mRootContext == null ) { @@ -185,31 +223,144 @@ public class Globals extends Application { @Override public void onCreate() { - // warn if we don't notice some binaries we need - for( String name : new String[] { "/system/bin/su" } ) { - File check = new File( name ); - try { - if( ! check.exists() ) { - Toast.makeText( this, "Failed to find file: " + name + ", SoftKeys may not function", Toast.LENGTH_LONG ).show(); + // init prefs defaults + PreferenceManager.setDefaultValues( this, R.xml.prefs, true ); + } + + // this used to be oncreate, but we can't have it there since we register for a boot receiver now + // since the only entry points are the receiver and keys, we'll run this from their oncreate or whatever + // and it will only run once then we'll flag it so we don't do it again + public void bootup() { + if( ! mBooted ) { + // warn if we don't notice some binaries we need + for( String name : new String[] { "/system/bin/su" } ) { + File check = new File( name ); + try { + if( ! check.exists() ) { + Toast.makeText( this, "Failed to find file: " + name + ", SoftKeys may not function", Toast.LENGTH_LONG ).show(); + } + }catch( Exception e ) { + Toast.makeText( this, "Unable to check for file: " + name, Toast.LENGTH_LONG ).show(); + } + + } + + android_id = Settings.Secure.getString(this.getContentResolver(), Settings.Secure.ANDROID_ID); + + // init the shell + try{ + getRootContext(); + }catch( Exception e ) { + Toast.makeText( this, "Failed to initialize root context", Toast.LENGTH_LONG ); + } + + restartService(); + initNotifications(); + mBooted = true; + } + } + + public void initNotifications() { + // Add notification buttons + SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences( this ); + if( ! didInitNotifications ) { + String ns = Context.NOTIFICATION_SERVICE; + NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns); + Context context = getApplicationContext(); + + // note: notification theming is kind of weird because of the way the notification manager + // handles icons, the icon in the bar itself when the status bar is closed HAS to come + // from the package creating the notification. We can however use any custom layouts + // for the actual notification when the bar is open. So if we are using custom notifications + // I just make the icon empty in the status bar which looks odd, but if we don't it would + // need to be an icon from this package and not from the theme which would mean the pull + // down notification would look different from the icon in the status bar itself which would + // be annoying. + // + // However is technically is possibly to theme these to an extent currently it's just + // not very ideal. + NotificationButton[] nb = new NotificationButton[ 5 ]; + Theme theme = new Theme( this, settings.getString( "theme", null ) ); + nb[ 0 ] = new NotificationButton( "SoftKeys", "nb_softkeys", + R.drawable.icon, + Intent.ACTION_MAIN ); + nb[ 1 ] = new NotificationButton( "Menu", "nb_menu", + theme.getRemoteViews( new String[] { "notification_menu" } ), + theme.getDrawable( new String[] { "notification_menu" } ), + R.drawable.button_menu, + Keys.ACTION_MENU ); + nb[ 2 ] = new NotificationButton( "Home", "nb_home", + theme.getRemoteViews( new String[] { "notification_home" } ), + theme.getDrawable( new String[] { "notification_home" } ), + R.drawable.button_home, + Keys.ACTION_HOME ); + nb[ 3 ] = new NotificationButton( "Back", "nb_back", + theme.getRemoteViews( new String[] { "notification_back" } ), + theme.getDrawable( new String[] { "notification_back" } ), + R.drawable.button_back, + Keys.ACTION_BACK ); + nb[ 4 ] = new NotificationButton( "Search", "nb_search", + theme.getRemoteViews( new String[] { "notification_search" } ), + theme.getDrawable( new String[] { "notification_search" } ), + R.drawable.button_search, + Keys.ACTION_SEARCH ); + + for( NotificationButton b : nb ) { + if( settings.getBoolean( b.mPrefKey, false ) ) { + Notification n = new Notification( b.mIconId, null, 0 ); + Intent si = new Intent( b.mAction ); + si.putExtra( "keyname", b.mExtraString ); + if( b.mAction == Intent.ACTION_MAIN ) { + si.setPackage( getPackageName() ); + }else{ + //si.setPackage( getPackageName() ); + si.setClass( this, Keys.class ); + } + PendingIntent i = PendingIntent.getActivity( this, 0, si, 0 ); + + // if we got a drawable but no view then set up our own remote view + // and add in their drawable + if( b.mView == null && b.mIcon != null ) { + b.mView = new RemoteViews( getPackageName(), R.layout.notification_bar_shortcut ); + // we run the drawable through resizeimage because that will rasterize it if it's + // not already a bitmapdrawable + b.mView.setImageViewBitmap( R.id.nb_image, + ((BitmapDrawable)Generator.resizeImage( b.mIcon, 48, 48 )).getBitmap() + ); + b.mView.setTextViewText( R.id.nb_text, "Press SoftKeys " + b.mButtonText + " Button" ); + } + + if( b.mView != null ) { + // discard icon, use the remote view instead + n.icon = -1; // this will make it draw a blank, this kind of sucks + // but looking through notificationmanager and statusbarservice + // you have to post some kind of icon, that id is based on the calling + // package, and that icon is always added to the bar + n.contentView = b.mView; + n.contentIntent = i; + }else{ + n.setLatestEventInfo( context, b.mButtonText, + b.mAction == Intent.ACTION_MAIN ? "Start SoftKeys" : + "Press SoftKeys " + b.mButtonText + " Button", i + ); + } + + //Notification n = new Notification(); + n.flags |= Notification.FLAG_NO_CLEAR; + + // we use the same icon id as the notification id since it should be unique, + // note the first parm here is a notification id we can use to reference/remove stuff + // we're not passing an icon here + mNotificationManager.notify( b.mIconId, n ); + }else{ + mNotificationManager.cancel( b.mIconId ); } - }catch( Exception e ) { - Toast.makeText( this, "Unable to check for file: " + name, Toast.LENGTH_LONG ).show(); } - + // this way every time you click a notification soft key it doesn't readd them all making + // them jump around as they are re-inserted + didInitNotifications = true; } - - android_id = Settings.Secure.getString(this.getContentResolver(), Settings.Secure.ANDROID_ID); - - // init the shell - try{ - getRootContext(); - }catch( Exception e ) { - Toast.makeText( this, "Failed to initialize root context", Toast.LENGTH_LONG ); - } - - restartService(); } - public void restartService() { // start the service this.stopService( new Intent( this, SoftKeysService.class ) ); diff --git a/src/net/hoopajoo/android/SoftKeys/Keys.java b/src/net/hoopajoo/android/SoftKeys/Keys.java index ddb87dc..fa25ba9 100644 --- a/src/net/hoopajoo/android/SoftKeys/Keys.java +++ b/src/net/hoopajoo/android/SoftKeys/Keys.java @@ -79,37 +79,6 @@ public class Keys extends Activity implements OnClickListener, OnLongClickListen private String homeaction; private int delayed_action_time; - - // simple typedef used to make the notifications a bit more generic - private class NotificationButton { - String mPrefKey; - RemoteViews mView; - int mIconId; - Drawable mIcon; - String mButtonText; - String mAction; - String mExtraString; - - NotificationButton( String text, String pref, RemoteViews view, Drawable d, int icon, String act, String extra ) { - mButtonText = text; - mPrefKey = pref; - mView = view; - mIconId = icon; - mIcon = d; - mAction = act; - mExtraString = extra; - } - - NotificationButton( String text, String pref, RemoteViews view, Drawable d, int icon, String act ) { - this( text, pref, view, d, icon, act, null ); - } - - NotificationButton( String text, String pref, int icon, String act ) { - this( text, pref, null, null, icon, act, null ); - } - - } - // For use by the service and this activity public static void applyButtons( SharedPreferences settings, View v, OnClickListener onClick, OnLongClickListener onLongClick ) { @@ -239,7 +208,7 @@ public class Keys extends Activity implements OnClickListener, OnLongClickListen public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - PreferenceManager.setDefaultValues( this, R.xml.prefs, true ); + ((Globals)getApplication()).bootup(); SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences( this ); setContentView( R.layout.main ); @@ -276,106 +245,6 @@ public class Keys extends Activity implements OnClickListener, OnLongClickListen }else{ findViewById( R.id.recent_apps ).setVisibility( View.GONE ); } - - // Add notification buttons - Globals app = (Globals)getApplication(); - if( ! app.didInitNotifications ) { - String ns = Context.NOTIFICATION_SERVICE; - NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns); - Context context = getApplicationContext(); - - // note: notification theming is kind of weird because of the way the notification manager - // handles icons, the icon in the bar itself when the status bar is closed HAS to come - // from the package creating the notification. We can however use any custom layouts - // for the actual notification when the bar is open. So if we are using custom notifications - // I just make the icon empty in the status bar which looks odd, but if we don't it would - // need to be an icon from this package and not from the theme which would mean the pull - // down notification would look different from the icon in the status bar itself which would - // be annoying. - // - // However is technically is possibly to theme these to an extent currently it's just - // not very ideal. - NotificationButton[] nb = new NotificationButton[ 5 ]; - Theme theme = new Theme( this, settings.getString( "theme", null ) ); - nb[ 0 ] = new NotificationButton( "SoftKeys", "nb_softkeys", - R.drawable.icon, - Intent.ACTION_MAIN ); - nb[ 1 ] = new NotificationButton( "Menu", "nb_menu", - theme.getRemoteViews( new String[] { "notification_menu" } ), - theme.getDrawable( new String[] { "notification_menu" } ), - R.drawable.button_menu, - ACTION_MENU ); - nb[ 2 ] = new NotificationButton( "Home", "nb_home", - theme.getRemoteViews( new String[] { "notification_home" } ), - theme.getDrawable( new String[] { "notification_home" } ), - R.drawable.button_home, - ACTION_HOME ); - nb[ 3 ] = new NotificationButton( "Back", "nb_back", - theme.getRemoteViews( new String[] { "notification_back" } ), - theme.getDrawable( new String[] { "notification_back" } ), - R.drawable.button_back, - ACTION_BACK ); - nb[ 4 ] = new NotificationButton( "Search", "nb_search", - theme.getRemoteViews( new String[] { "notification_search" } ), - theme.getDrawable( new String[] { "notification_search" } ), - R.drawable.button_search, - ACTION_SEARCH ); - - for( NotificationButton b : nb ) { - if( settings.getBoolean( b.mPrefKey, false ) ) { - Notification n = new Notification( b.mIconId, null, 0 ); - Intent si = new Intent( b.mAction ); - si.putExtra( "keyname", b.mExtraString ); - if( b.mAction == Intent.ACTION_MAIN ) { - si.setPackage( getPackageName() ); - }else{ - //si.setPackage( getPackageName() ); - si.setClass( this, Keys.class ); - } - PendingIntent i = PendingIntent.getActivity( this, 0, si, 0 ); - - // if we got a drawable but no view then set up our own remote view - // and add in their drawable - if( b.mView == null && b.mIcon != null ) { - b.mView = new RemoteViews( getPackageName(), R.layout.notification_bar_shortcut ); - // we run the drawable through resizeimage because that will rasterize it if it's - // not already a bitmapdrawable - b.mView.setImageViewBitmap( R.id.nb_image, - ((BitmapDrawable)Generator.resizeImage( b.mIcon, 48, 48 )).getBitmap() - ); - b.mView.setTextViewText( R.id.nb_text, "Press SoftKeys " + b.mButtonText + " Button" ); - } - - if( b.mView != null ) { - // discard icon, use the remote view instead - n.icon = -1; // this will make it draw a blank, this kind of sucks - // but looking through notificationmanager and statusbarservice - // you have to post some kind of icon, that id is based on the calling - // package, and that icon is always added to the bar - n.contentView = b.mView; - n.contentIntent = i; - }else{ - n.setLatestEventInfo( context, b.mButtonText, - b.mAction == Intent.ACTION_MAIN ? "Start SoftKeys" : - "Press SoftKeys " + b.mButtonText + " Button", i - ); - } - - //Notification n = new Notification(); - n.flags |= Notification.FLAG_NO_CLEAR; - - // we use the same icon id as the notification id since it should be unique, - // note the first parm here is a notification id we can use to reference/remove stuff - // we're not passing an icon here - mNotificationManager.notify( b.mIconId, n ); - }else{ - mNotificationManager.cancel( b.mIconId ); - } - } - // this way every time you click a notification soft key it doesn't readd them all making - // them jump around as they are re-inserted - app.didInitNotifications = true; - } return_after_back = settings.getBoolean( "return_home_after_back", false ); delayed_action = new Runnable() { @@ -420,6 +289,8 @@ public class Keys extends Activity implements OnClickListener, OnLongClickListen } + Globals app = ((Globals)getApplication()); + //d( "Updating last version code: " + force_level ); if( settings.getInt( "last_intro_level", 0 ) < force_level ) { Intent intent = new Intent( this, QuickDoc.class ); @@ -730,6 +601,7 @@ public class Keys extends Activity implements OnClickListener, OnLongClickListen // redo notification buttons ((Globals)getApplication()).didInitNotifications = false; ((Globals)getApplication()).restartService(); + ((Globals)getApplication()).initNotifications(); startActivity( new Intent( this, Keys.class ) ); } diff --git a/src/net/hoopajoo/android/SoftKeys/SoftKeysService.java b/src/net/hoopajoo/android/SoftKeys/SoftKeysService.java index e75cbf5..d339d22 100644 --- a/src/net/hoopajoo/android/SoftKeys/SoftKeysService.java +++ b/src/net/hoopajoo/android/SoftKeys/SoftKeysService.java @@ -75,7 +75,7 @@ public class SoftKeysService extends Service { private int mNumDrags; private OrientationEventListener mOrientationListener; private Runnable mUpdateDrag; - + private int mNumRows = 0; private Map<Integer,Integer> mCustomKeys = new HashMap<Integer,Integer>(); @@ -88,6 +88,7 @@ public class SoftKeysService extends Service { @Override public void onCreate() { super.onCreate(); + ((Globals)getApplication()).bootup(); OnClickListener c = new OnClickListener() { @Override @@ -300,7 +301,9 @@ public class SoftKeysService extends Service { mView.setOnLongClickListener( longpress_rotate ); // only drag by the exit button now - mView.findViewById( R.id.exit ).setOnTouchListener( touch ); + if( settings.getBoolean( "service_drag", true ) ) { + mView.findViewById( R.id.exit ).setOnTouchListener( touch ); + } mView.findViewById( R.id.exit ).setOnLongClickListener( longpress_rotate ); /* For when long click motionevent is fixed @@ -319,7 +322,6 @@ public class SoftKeysService extends Service { // 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", @@ -327,7 +329,10 @@ public class SoftKeysService extends Service { new int[] { R.id.popper } ); ImageButton b = (ImageButton)mBumpView.findViewById( R.id.popper ); - b.setOnTouchListener( touch ); + if( settings.getBoolean( "service_drag_popper", true ) ) { + mBumpView.setOnTouchListener( touch ); + b.setOnTouchListener( touch ); + } // apply alpha applyTransparency( mBumpView, settings.getInt( "service_popper_transparency", 0 ) ); @@ -354,7 +359,9 @@ public class SoftKeysService extends Service { Generator.currentTheme( this ), Generator.scaledIconSize( this, 0, buttonMult ) ); - mExtraView.setOnTouchListener( touch ); + if( settings.getBoolean( "service_drag_extra", true ) ) { + mExtraView.setOnTouchListener( touch ); + } OnLongClickListener configButtons = new OnLongClickListener() { @Override |