text: /* 
   * This file is part of the RootTools Project: http://code.google.com/p/roottools/
   *  
   * Copyright (c) 2012 Stephen Erickson, Chris Ravenscroft, Dominik Schuermann, Adam Shanks
   *  
   * This code is dual-licensed under the terms of the Apache License Version 2.0 and
   * the terms of the General Public License (GPL) Version 2.
   * You may use this code according to either of these licenses as is most appropriate
   * for your project on a case-by-case basis.
   * 
   * The terms of each license can be found in the root directory of this project's repository as well as at:
   * 
   * * http://www.apache.org/licenses/LICENSE-2.0
   * * http://www.gnu.org/licenses/gpl-2.0.txt
   *  
   * Unless required by applicable law or agreed to in writing, software
   * distributed under these Licenses is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See each License for the specific language governing permissions and
   * limitations under that License.
   */
  
  package com.nearucenterplaza.redenvelopeassistant.utils.rootbox.execution;
  
  import android.content.Context;
  import android.os.Bundle;
  import android.os.Handler;
  import android.os.Looper;
  import android.os.Message;
  
  import java.io.IOException;
  
  import com.nearucenterplaza.redenvelopeassistant.utils.rootbox.RootTools;
  
  
  public abstract class Command
  {
  
      ExecutionMonitor executionMonitor = null;
      Handler mHandler = null;
      boolean executing = false;
  
      String[] command = {};
      boolean javaCommand = false;
      Context context = null;
      boolean finished = false;
      boolean terminated = false;
      boolean handlerEnabled = true;
      int exitCode = -1;
      int id = 0;
      int timeout = RootTools.default_Command_Timeout;
  
      public abstract void commandOutput(int id, String line);
  
      public abstract void commandTerminated(int id, String reason);
  
      public abstract void commandCompleted(int id, int exitCode);
  
      /**
       * Constructor for executing a normal shell command
       *
       * @param id      the id of the command being executed
       * @param command the command, or commands, to be executed.
       */
      public Command(int id, String... command)
      {
          this.command = command;
          this.id = id;
  
          createHandler(RootTools.handlerEnabled);
      }
  
      /**
       * Constructor for executing a normal shell command
       *
       * @param id             the id of the command being executed
       * @param handlerEnabled when true the handler will be used to call the
       *                       callback methods if possible.
       * @param command        the command, or commands, to be executed.
       */
      public Command(int id, boolean handlerEnabled, String... command)
      {
          this.command = command;
          this.id = id;
  
          createHandler(handlerEnabled);
      }
  
      /**
       * Constructor for executing a normal shell command
       *
       * @param id      the id of the command being executed
       * @param timeout the time allowed before the shell will give up executing the command
       *                and throw a TimeoutException.
       * @param command the command, or commands, to be executed.
       */
      public Command(int id, int timeout, String... command)
      {
          this.command = command;
          this.id = id;
          this.timeout = timeout;
  
          createHandler(RootTools.handlerEnabled);
      }
  
      /**
       * Constructor for executing Java commands rather than binaries
       *
       * @param javaCommand when True, it is a java command.
       * @param context     needed to execute java command.
       */
      public Command(int id, boolean javaCommand, Context context, String... command)
      {
          this(id, command);
          this.javaCommand = javaCommand;
          this.context = context;
      }
  
      /**
       * Constructor for executing Java commands rather than binaries
       *
       * @param javaCommand when True, it is a java command.
       * @param context     needed to execute java command.
       */
      public Command(int id, boolean handlerEnabled, boolean javaCommand, Context context, String... command)
      {
          this(id, handlerEnabled, command);
          this.javaCommand = javaCommand;
          this.context = context;
      }
  
      /**
       * Constructor for executing Java commands rather than binaries
       *
       * @param javaCommand when True, it is a java command.
       * @param context     needed to execute java command.
       */
      public Command(int id, int timeout, boolean javaCommand, Context context, String... command)
      {
          this(id, timeout, command);
          this.javaCommand = javaCommand;
          this.context = context;
      }
  
      protected void finishCommand()
      {
          executing = false;
          finished = true;
          this.notifyAll();
      }
  
      protected void commandFinished()
      {
          if (!terminated)
          {
              synchronized (this)
              {
                  if (mHandler != null && handlerEnabled)
                  {
                      Message msg = mHandler.obtainMessage();
                      Bundle bundle = new Bundle();
                      bundle.putInt(CommandHandler.ACTION, CommandHandler.COMMAND_COMPLETED);
                      msg.setData(bundle);
                      mHandler.sendMessage(msg);
                  }
                  else
                  {
                      commandCompleted(id, exitCode);
                  }
  
                  RootTools.log("Command " + id + " finished.");
                  finishCommand();
              }
          }
      }
  
      private void createHandler(boolean handlerEnabled)
      {
  
          this.handlerEnabled = handlerEnabled;
  
          if (Looper.myLooper() != null && handlerEnabled)
          {
              RootTools.log("CommandHandler created");
              mHandler = new CommandHandler();
          }
          else
          {
              RootTools.log("CommandHandler not created");
          }
      }
  
      public String getCommand()
      {
          StringBuilder sb = new StringBuilder();
  
          if (javaCommand)
          {
              String filePath = context.getFilesDir().getPath();
              for (int i = 0; i < command.length; i++)
              {
  
                  if (i > 0)
                  {
                      sb.append('\n');
                  }
  
                  /*
                   * TODO Make withFramework optional for applications
                   * that do not require access to the fw. -CFR
                   */
                  sb.append(
                          "dalvikvm -cp " + filePath + "/anbuild.dex"
                                  + " com.android.internal.util.WithFramework"
                                  + " RootClass "
                                  + command[i]);
              }
          }
          else
          {
              for (int i = 0; i < command.length; i++)
              {
                  if (i > 0)
                  {
                      sb.append('\n');
                  }
  
                  sb.append(command[i]);
              }
          }
          return sb.toString();
      }
  
      public boolean isExecuting()
      {
          return executing;
      }
  
      public boolean isHandlerEnabled()
      {
          return handlerEnabled;
      }
  
      public boolean isFinished()
      {
          return finished;
      }
  
      public int getExitCode()
      {
          return this.exitCode;
      }
  
      protected void setExitCode(int code)
      {
          synchronized (this)
          {
              exitCode = code;
          }
      }
  
      protected void startExecution()
      {
          executionMonitor = new ExecutionMonitor();
          executionMonitor.setPriority(Thread.MIN_PRIORITY);
          executionMonitor.start();
          executing = true;
      }
  
      public void terminate(String reason)
      {
          try
          {
              Shell.closeAll();
              RootTools.log("Terminating all shells.");
              terminated(reason);
          }
          catch (IOException e)
          {
          }
      }
  
      protected void terminated(String reason)
      {
          synchronized (Command.this)
          {
  
  
              if (mHandler != null && handlerEnabled)
              {
                  Message msg = mHandler.obtainMessage();
                  Bundle bundle = new Bundle();
                  bundle.putInt(CommandHandler.ACTION, CommandHandler.COMMAND_TERMINATED);
                  bundle.putString(CommandHandler.TEXT, reason);
                  msg.setData(bundle);
                  mHandler.sendMessage(msg);
              }
              else
              {
                  commandTerminated(id, reason);
              }
  
              RootTools.log("Command " + id + " did not finish because it was terminated. Termination reason: " + reason);
              setExitCode(-1);
              terminated = true;
              finishCommand();
          }
      }
  
      protected void output(int id, String line)
      {
          if (mHandler != null && handlerEnabled)
          {
              Message msg = mHandler.obtainMessage();
              Bundle bundle = new Bundle();
              bundle.putInt(CommandHandler.ACTION, CommandHandler.COMMAND_OUTPUT);
              bundle.putString(CommandHandler.TEXT, line);
              msg.setData(bundle);
              mHandler.sendMessage(msg);
          }
          else
          {
              commandOutput(id, line);
          }
      }
  
      private class ExecutionMonitor extends Thread
      {
          public void run()
          {
              while (!finished)
              {
  
                  synchronized (Command.this)
                  {
                      try
                      {
                          Command.this.wait(timeout);
                      }
                      catch (InterruptedException e)
                      {
                      }
                  }
  
                  if (!finished)
                  {
                      RootTools.log("Timeout Exception has occurred.");
                      terminate("Timeout Exception");
                  }
              }
          }
      }
  
      private class CommandHandler extends Handler
      {
          static final public String ACTION = "action";
          static final public String TEXT = "text";
  
          static final public int COMMAND_OUTPUT = 0x01;
          static final public int COMMAND_COMPLETED = 0x02;
          static final public int COMMAND_TERMINATED = 0x03;
  
          public void handleMessage(Message msg)
          {
              int action = msg.getData().getInt(ACTION);
              String text = msg.getData().getString(TEXT);
  
              switch (action)
              {
                  case COMMAND_OUTPUT:
                      commandOutput(id, text);
                      break;
                  case COMMAND_COMPLETED:
                      commandCompleted(id, exitCode);
                      break;
                  case COMMAND_TERMINATED:
                      commandTerminated(id, text);
                      break;
              }
          }
      }
  }
  