Sunday, February 20, 2011

How to get root access and execute commands in your Android application ?



Well, I've tried executing several commands that required root access in my Android application (AutomateIt) and found several partial solutions online (especially this one), which helped me a lot but were still missing something to make them more robust and reusable.
Since I try making things very generic and easy to use, I constructed a class that handles most of the things required to execute commands from your Android application after getting root privileges. All you need to do is extend this class and implement one simple method that returns a list of all the commands you wish to execute (getCommandsToExecute).

The class also provides a static service that can be used to determine whether the application has root access or not. Note that when calling the static service, it actually requests for root access and returns the result to that request.
public abstract class ExecuteAsRootBase
{
   public static boolean canRunRootCommands()
   {
      boolean retval = false;
      Process suProcess;

      try
      {
         suProcess = Runtime.getRuntime().exec("su");

         DataOutputStream os = new DataOutputStream(suProcess.getOutputStream());
         DataInputStream osRes = new DataInputStream(suProcess.getInputStream());

         if (null != os && null != osRes)
         {
            // Getting the id of the current user to check if this is root
            os.writeBytes("id\n");
            os.flush();

            String currUid = osRes.readLine();
            boolean exitSu = false;
            if (null == currUid)
            {
               retval = false;
               exitSu = false;
               Log.d("ROOT", "Can't get root access or denied by user");
            }
            else if (true == currUid.contains("uid=0"))
            {
               retval = true;
               exitSu = true;
               Log.d("ROOT", "Root access granted");
            }
            else
            {
               retval = false;
               exitSu = true;
               Log.d("ROOT", "Root access rejected: " + currUid);
            }

            if (exitSu)
            {
               os.writeBytes("exit\n");
               os.flush();
            }
         }
      }
      catch (Exception e)
      {
         // Can't get root !
         // Probably broken pipe exception on trying to write to output stream (os) after su failed, meaning that the device is not rooted

         retval = false;
         Log.d("ROOT", "Root access rejected [" + e.getClass().getName() + "] : " + e.getMessage());
      }

      return retval;
   }
   
   public final boolean execute()
   {
      boolean retval = false;
      
      try
      {
         ArrayList<String> commands = getCommandsToExecute();
         if (null != commands && commands.size() > 0)
         {
            Process suProcess = Runtime.getRuntime().exec("su");

            DataOutputStream os = new DataOutputStream(suProcess.getOutputStream());

            // Execute commands that require root access
            for (String currCommand : commands)
            {
               os.writeBytes(currCommand + "\n");
               os.flush();
            }

            os.writeBytes("exit\n");
            os.flush();

            try
            {
               int suProcessRetval = suProcess.waitFor();
               if (255 != suProcessRetval)
               {
                  // Root access granted
                  retval = true;
               }
               else
               {
                  // Root access denied
                  retval = false;
               }
            }
            catch (Exception ex)
            {
               Log.e("ROOT", "Error executing root action", ex);
            }
         }
      }
      catch (IOException ex)
      {
         Log.w("ROOT", "Can't get root access", ex);
      }
      catch (SecurityException ex)
      {
         Log.w("ROOT", "Can't get root access", ex);
      }
      catch (Exception ex)
      {
         Log.w("ROOT", "Error executing internal operation", ex);
      }
      
      return retval;
   }
   protected abstract ArrayList<String> getCommandsToExecute();
}

Wednesday, February 16, 2011

AutomateIt - Automate Your Android !




Visit our new website at http://www.automateitapp.com


AutomateIt is a simple, easy-to-use yet powerful automation tool for android.
The application lets you define a set of your desired behaviors in response to events on your Android device.
Each behavior/rule is defined as a pair of Trigger-Action listed below.

(See reviews in different languages on the bottom of this page)

Click here for a short demo video, or check out the advanced features of AutomateIt Pro !


Currently supports the following triggers:
* Any SMS Trigger - Triggers on SMS received
* SMS With Text Trigger - Triggers on receipt of SMS Message with a specific text
* Battery Level Trigger - Triggers on a defined battery level
* Bluetooth State Enabled/Disabled
* Bluetooth Device Connected - Any device or specific device
* Incoming/Hang Call - Any call or from a specific contact
* Headset Plugged/Unplugged Trigger
* Location Trigger - Entering/Exiting a defined region (See Location Trigger Tips & Tricks post)
* External Power Connected/Disconnected
* Screen On/Off
* Wi-Fi Enabled/Disabled
* Connected to Wi-Fi network - Any network or a specific network
* Time Trigger - recurring time events
* Background data settings changed - enabling or disabling the background data setting
* GPS Enabled Changed - GPS Activated/Deactivated and started/stopped looking for current location
* SMS from contact
* Airplane Mode Activated/Deactivated
* Dock State Trigger - Docked to Car/Desk
* Application Status Trigger - Triggers when selected application activated or deactivated
* Outgoing call - all calls or calling specific contact
* Sound Mode Changed
* Boot Trigger - triggers on device startup (assuming service starts on boot)
* Manual Trigger - Requires user explicit execution of this trigger
* Cell ID Trigger - Trigger when connecting or disconnecting from defined cellular cells (Limited functionality - only allows saving a single set of cells as pre-defined location)
* NFC Trigger - Use NFC Tags to launch rules

Currently supports the following actions:
* Notification - Shows notification on notification bar
* Play Sound - Plays selected sound
* Set Bluetooth State - Enabled/Disabled
Set Sound Mode - Silent / Vibrate / Normal(With/Without Vibrate)
* Set Speakerphone State - Turn on/off
* Set Volume - Sets volume of all streams or a specific stream
* Set Wi-Fi Adapter State - Enabled/Disabled
* Start Application
* Enable/Disable other rules
* Vibrate action
* Enable/Disable Data Connectivity action - notice that this does not change your APN or background data state but actually cancels the data connectivity [Not supported for Android version 2.3 and up. see here why]
* Kill application [Requires Root - See here why]
* Launch Home Screen
* Activate/Deactivate Airplane mode
* Enable/Disable GPS [Supported for Android version prior to 2.3 and MOST rooted devices. Not supported for ICS]
* Enable/Disable Sync Data [Supported for Android version prior to 2.3 and MOST rooted devices. Not supported for ICS]
* Set Mobile Data - Enable/Disable Mobile Data
* Set Screen Brightness - Automatic or specific value
* Enable/Disable screen automatic rotation
* Dial Phone Number
* Send SMS to phone number (Message text can include keywords - Location or Battery level)
* Set screen timeout (Including "Never" turn off)
* Shutdown Device [Requires Root]
* Text-to-Speech - Say defined text
* Reboot [Requires Root]


Unlike similar applications you can find, there is no limitation on the number of rules you can define !
See list of some very useful rules at this post.
This application is still being expanded to support new triggers and actions and suggestions or request for such are appreciated (although, obviously I can't guarantee that they all will be implemented...)
Here are some screenshots and a short manual for this very easy to use application:
On the first time you launch the application you'll get this empty screen saying that there are no rules defined:
The first thing you'd want to do, is define some rules (just a reminder, a rule is a pair of trigger-action). You can do it by pressing the button on the top-left side of the screen or from the options menu as seen on the right image above.
The new rule screen lets you pick a trigger and an action for your new rule, by clicking the selection box of each:
The list of available triggers and actions is dependent on your device and you will not see triggers and actions that your device does not support (For instance, if your device has no Bluetooth capability, no Bluetooth related triggers or actions will be available for selection). This is a partial list of the available triggers and action:
Once a trigger or action is selected, the image on the right side of the selection box will change (in most cases), allowing you to further configure the selected trigger or action.
Not all triggers or actions can be configured (one example is the "Power Connected Trigger").
One of the most simple (and usable) rules you can define is turning on your Bluetooth adapter when external power is connected to your device as can be seen on the next screenshot:


All that's left to do is save the rule by pressing the "Save" button on the top-left side of the screen or from the options menu.

That's it ! you've defined your first rule !


Rule Delayed Execution
The "Delayed Execution" check box that you've seen on the screenshot above lets you define a rule such that once the trigger is activated, a countdown starts until the action is executed.
One good use of that functionality is to turn off your data connectivity a few minutes after the screen is turned off.
The default delay is set to 5 minutes (can be changed from the settings screen described below) but it is defined for each rule:
Since during the delay you might want to see when the action is going to be executed or cancel the delayed execution, as soon as the trigger is activated, a notification message will appear in the status bar showing the progress of the currently waiting action. Clicking on the notification will cancel the delayed execution and remove the notification:

Rule Operations (Edit, Delete...)
After defining a new rule, it can be edited by pressing the "Edit" button or anywhere on the rule row (excluding the "Delete" button...).


Long press on the rule row will bring up a context menu allowing you to edit/delete or enable/disable the rule (New Feature on version 1.16.0 - Show Rule History. New Feature on version 1.17.0 - Share Rule. see details below):
Once the rule is disabled the application's service will not monitor the defined trigger, thus will not execute the defined action. This can be very useful for defining a set of rules that you only want enabled in specific times.
Editing Triggers and Actions
Since the list of available triggers and actions is very long, I will not review all of them here but only a small portion of them.
Basically, The only difference between one trigger/action to another is the detailed configuration of each.
Some examples:
  1. Using the "SMS From Contact Trigger", you can select the specific contact from which you receive the SMS Message
  2. Using the "Location Trigger" requires you to select the target location, proximity radius around the target location, sampling rate and whether you are entering or exiting the defined region (you can also toggle the map size to full screen, go to address or location, go to your last location, show satellite layer etc). See more details here.
  3. Using the "Time Trigger" requires you to select the time of day and the days of the week in which the trigger will fire.
  4. Using the "Play Sound Action" requires you to select the sound to play
  5. Using the "Start Application Action" requires you to select the application to start
  6. Using the Wifi/Bluetooth triggers/actions requires you to select the Wifi/Bluetooth state
  7. Using the "Notification Action" lets you enter the notification title, text and various notification parameters


One special action is the "Enable/Disable Rule Action" which based on any trigger, lets you enable or disable specific rule.

Triggered Rules History
The application saves the history of triggered rules so you can keep track of which rule was triggered, and when. The default history size is set to the last 30 events and you can change that setting from the settings screen. From the screen's menu you can export the triggered rules history to a CSV file or clear the history. by clicking on the "History" icon of each rule you can see its history records (more details below):


Backup and Restore
From the main screen context menu you can backup and restore your rules (press the "More" button).
All backups are stored on your external storage (/sdcard/AutomateIt/Backups) and will be kept even if you uninstall the application.

Application Settings

You can also customize some of the application settings from the settings screen (opened from the options menu on the main screen):
The settings you can customize include:
  • Display settings for main screen (show/hide trigger and action information)
  • Service settings - Show/Hide task bar notification icon, start/stop service and toggle service start on boot
  • Default settings for location triggers (for more details on those settings click here)
  • Whether time triggers wake the device or not
  • Triggered rules history size
  • Default delayed execution time
  • New feature 1.19.0 - Language Settings (See details below)
  • Debug & Help settings
The language settings section is quite easy to use and allows you to customize AutomateIt to your desired language. The following settings are available:


  • Use default language - When this checkbox is checked (default), AutomateIt will use your default language if it is supported (otherwise, it will use English).
  • If the "Use default language" checkbox is not checked, you can choose one of the supported language. the selected language will be used once you exit the settings screen.
  • Flip Right-To-Left - This option is only relevant for languages that requires right-to-left reading order and the installed ROM does not support it (keeps text aligned to the left). Other languages are not affected by this setting.
Want to have another language supported ? See a spelling mistake that should be fixed ? What languages are already supported ? Click here for more details.

Rule History
New Feature on version 1.16.0 - Each rule now has its own history log that can help you keep track of events related to your rules. The following events will be logged to the rule history:
  • Rule created
  • Rule edited
  • Rule enabled/disabled (from context menu or by other rule)
  • Rule triggered
  • Rule started countdown for delayed execution
  • Rule delayed execution was canceled
  • Rule manually executed by user
  • Rules with Location Trigger specific events - click here
  • [Pro version only]: Rule active period started
  • [Pro version only]: Rule active period ended
Rule history can be accessed by context menu on the main screen or the history screen as shown in the images above. It can also be accessed from the "Edit rule" screen using the icon on the top-right or from the screen menu:
Rule Sharing and Import
New Feature on version 1.17.0 - Rule sharing and improved restore from backup.
Sharing rules with other users can be performed from each rule context menu (long-press the rule record on the main screen and select "Share Rule") or by selecting the "Share Rules" option from the main screen menu, which will display the following selection dialog:
By default, all rules are checked. Once you click the "OK" button, a "shared rules file" will be created at /sdcard/AutomateIt/shared and you'll be required to select how the rules will be shared (probably an email application).
Assuming the rules were shared by email, The recipient of the email will be required to save the attached shared rules file and open it using any file browser (Astro file manager, ES File Explorer etc). As the shared rules file is opened, the following selection box will be displayed allowing you to choose which rules should be imported:
Notice that by clicking the "Replace Existing" button all existing rules will be deleted and replaced by the selected rules, while clicking the "Add to Existing" will add the selected rules to your already existing rules (Duplicate rules will not be created).
The same selection dialog will be displayed when using the "Restore Rules" option on the main screen menu, allowing you to selectively restore from your backups.
Note: Rules with features only available on the Pro version can't be shared with the free version.

New Feature on version 1.18.0 - Widgets !
This new feature lets you access your defined rules from your home screen and perform different things with those rules. AutomateIt widgets are added to the home screen just as you would add any other widget. Once you select to add an AutomateIt widget, the following configuration screen is displayed:
This display has several selection lists that are required to configure your widget:


  • Rule - Which rule this widget targets ?
  • Widget Action - What will happen when I click on the widget ? there are 3 options - Perform Rule Action (default), Toggle Enable/Disable Rule and Show Rule History. Notice that changing the widget action will change the small gray icon on the widget display.
  • Widget Icon - How will the widget look like ? You can select one of 3 icons - Action Icon (default), Trigger Icon and Application Icon
  • Show Rule Name - Will the widget display include the rule name or it is just an icon ?
Once you finished configuring your widget, click on the "Create Widget" button. Here are a few sample widgets:

For some frequently asked questions, see this post or visit AutomateIt thread on xda-developers.com.

That's about it :-)
Enjoy.
Download from AppBrain.com:
Reviews:

Change log:
[2011, Mar 11 - Update to version 1.7.0]
[2011, Mar 19 - Update to version 1.8.0]
[2011, Mar 26 - Update to version 1.9.0]
[2011, Apr 9 - Update to version 1.10.0]
[2011, Apr 18 - Update to version 1.11.0]
[2011, Apr 22 - Update to version 1.12.0]
[2011, May 7 - Update to version 1.13.0]
[2011, May 16 - Update to version 1.14.0]
[2011, June 9 - Update to version 1.14.7]
[2011, June 20 - Update to version 1.15.0]
[2011, June 28 - Update to version 1.16.0]
[2011, July 5 - Update to version 1.17.0]
[2011, July 12 - Update to version 1.18.0]
[2011, Aug 16 - Update to version 1.19.0]
[2012, July 4 - Update to version 1.22.0]