content: /*----------------------------------------------------------------------------+
   *|                                                                           |
   *|                          Android's Hooker                                 |
   *|                                                                           |
   *+---------------------------------------------------------------------------+
   *| Copyright (C) 2011 Georges Bossert and Dimitri Kirchner                   |
   *| 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/>.      |
   *+---------------------------------------------------------------------------+
   *| @url      : http://www.amossys.fr                                         |
   *| @contact  : android-hooker@amossys.fr                                     |
   *| @sponsors : Amossys, http://www.amossys.fr                                |
   *+---------------------------------------------------------------------------+
   */
   
  package com.amossys.hooker.hookers;
  
  import java.util.HashMap;
  import java.util.Map;
  
  import com.amossys.hooker.SubstrateMain;
  import com.amossys.hooker.exceptions.HookerInitializationException;
  
  
  /**
   * Hooker for MediaRecorder.
   * Attach on Android Camera API (PackageManager.hasSystemFeature is captured by PackageManager hooker).
   * Attach on MediaRecorder class (for microphone for example).
   * @author Dimitri Kirchner
   *
   */
  public class MediaRecorderHooker extends Hooker {
  
    public static final String NAME = "MediaRecorder";
  
    public MediaRecorderHooker() {
      super(MediaRecorderHooker.NAME);
    }
  
    @Override
    public void attach() {
      attachOnCameraClass();
      attachOnAudioRecordClass();
      attachOnAudioManagerClass();
      //We cannot hook the class MediaRecorder, since it is deeply related to JNI.
      //attachOnMediaRecorderClass();
    }
    
    /**
     * Attach on Camera class
     */
    private void attachOnCameraClass() {
  	final String className = "android.hardware.Camera";
  	  
      Map<String, Integer> methodsToHook = new HashMap<String, Integer>();
  
      methodsToHook.put("open", 2);
      methodsToHook.put("getParameters", 1);
      methodsToHook.put("setParameters", 2);
      methodsToHook.put("startPreview", 1);
      methodsToHook.put("takePicture", 2);
      methodsToHook.put("release", 0);
      methodsToHook.put("enableShutterSound", 2);
      methodsToHook.put("getCameraInfo", 1);
      methodsToHook.put("getNumberOfCameras", 1);
      methodsToHook.put("lock", 2);
      methodsToHook.put("reconnect", 2);
      methodsToHook.put("setFaceDetectionListener", 2);
      methodsToHook.put("startFaceDetection", 2);
  
      try {
  		hookMethods(null, className, methodsToHook);
  		SubstrateMain.log(new StringBuilder("hooking ").append(className)
  				.append(" methods sucessful").toString());
  
  	} catch (HookerInitializationException e) {
  		SubstrateMain.log(new StringBuilder("hooking ").append(className)
  				.append(" methods has failed").toString(), e);
  	}
      
    }
    
    private void attachOnAudioRecordClass() {
  		final String className = "android.media.AudioRecord";
  
  		Map<String, Integer> methodsToHook = new HashMap<String, Integer>();
  
  		methodsToHook.put("getAudioFormat", 0);
  		methodsToHook.put("getAudioSessionId", 0);
  		methodsToHook.put("getAudioSource", 0);
  		methodsToHook.put("getChannelConfiguration", 0);
  		methodsToHook.put("getChannelCount", 0);
  		methodsToHook.put("getRecordingState", 0);
  		methodsToHook.put("getState", 0);
  		methodsToHook.put("read", 1);
  		methodsToHook.put("release", 0);
  		methodsToHook.put("setNotificationMarkerPosition", 1);
  		methodsToHook.put("setPositionNotificationPeriod", 1);
  		methodsToHook.put("setRecordPositionUpdateListener", 1);
  		methodsToHook.put("startRecording", 2);
  		methodsToHook.put("stop", 0);
  
  		try {
  			hookMethods(null, className, methodsToHook);
  			SubstrateMain.log(new StringBuilder("hooking ").append(className)
  					.append(" methods sucessful").toString());
  
  		} catch (HookerInitializationException e) {
  			SubstrateMain.log(new StringBuilder("hooking ").append(className)
  					.append(" methods has failed").toString(), e);
  		}
  	}
  
    private void attachOnAudioManagerClass() {
  		final String className = "android.media.AudioManager";
  
  		Map<String, Integer> methodsToHook = new HashMap<String, Integer>();
  
  		methodsToHook.put("getParameters", 0);
  		methodsToHook.put("getProperty", 0);
  		methodsToHook.put("isMicrophoneMute", 0);
  		methodsToHook.put("isSpeakerphoneOn", 0);
  		methodsToHook.put("registerMediaButtonEventReceiver", 0);
  		methodsToHook.put("registerRemoteControlClient", 0);
  		methodsToHook.put("registerRemoteController", 0);
  		methodsToHook.put("setParameters", 1);
  		methodsToHook.put("setRingerMode", 0);
  		methodsToHook.put("setSpeakerphoneOn", 2);
  		methodsToHook.put("setRouting", 2);
  		methodsToHook.put("setStreamMute", 1);
  		methodsToHook.put("setStreamSolo", 1);
  		methodsToHook.put("setStreamVolume", 1);
  
  		try {
  			hookMethods(null, className, methodsToHook);
  			SubstrateMain.log(new StringBuilder("hooking ").append(className)
  					.append(" methods sucessful").toString());
  
  		} catch (HookerInitializationException e) {
  			SubstrateMain.log(new StringBuilder("hooking ").append(className)
  					.append(" methods has failed").toString(), e);
  		}
  	}
  	
    
    /**
     * Attach on MediaRecorder class
     */
    @SuppressWarnings("unused")
    private void attachOnMediaRecorderClass() {
      Map<String, Integer> methodsToHook = new HashMap<String, Integer>();
  
  
      methodsToHook.put("setOutputFile", 2);
      methodsToHook.put("prepare", 1);
      methodsToHook.put("reset", 2);
  	  methodsToHook.put("setLocation", 2); //From 4.0.1 r1
  	  methodsToHook.put("setAudioChannels", 2); //From 2.3
  	  
  //  methodsToHook.put("setCamera", 2); //This is native method.
  //  methodsToHook.put("setAudioSource", 2); //native
  //  methodsToHook.put("setOutputFormat", 1); //native
  //  methodsToHook.put("start", 2); //native
  //  methodsToHook.put("stop", 0); //native
  
  
      try {
        hookMethods(null, "android.media.MediaRecorder",
          methodsToHook);
        SubstrateMain.log("hooking android.media.MediaRecorder methods sucessful");
  
      } catch (HookerInitializationException e) {
        SubstrateMain.log("hooking android.media.MediaRecorder methods has failed", e);
      }
      
    }
    
  }
  