@Override
  public Type appliesInternal(AndroidMethod method) {
    SootMethod sm = getSootMethod(method);

    if (sm == null) {
      System.err.println("Method not declared: " + method);
      return Type.NOT_SUPPORTED;
    }

    // We are only interested in setters
    if (!sm.isConcrete()) return Type.NOT_SUPPORTED;

    try {
      Set<Value> paramVals = new HashSet<Value>();
      for (Unit u : sm.retrieveActiveBody().getUnits()) {
        // Collect the parameters
        if (u instanceof IdentityStmt) {
          IdentityStmt id = (IdentityStmt) u;
          if (id.getRightOp() instanceof ParameterRef) paramVals.add(id.getLeftOp());
        }

        // Check for invocations
        if (u instanceof Stmt) {
          Stmt stmt = (Stmt) u;
          if (stmt.containsInvokeExpr())
            if (stmt.getInvokeExpr() instanceof InstanceInvokeExpr) {
              InstanceInvokeExpr iinv = (InstanceInvokeExpr) stmt.getInvokeExpr();
              if (paramVals.contains(iinv.getBase()))
                if (iinv.getMethod().getName().startsWith(methodName)) return Type.TRUE;
            }
        }
      }
      return Type.FALSE;
    } catch (Exception ex) {
      System.err.println("Something went wrong:");
      ex.printStackTrace();
      return Type.NOT_SUPPORTED;
    }
  }
  @Override
  public Type appliesInternal(AndroidMethod method) {
    SootMethod sm = getSootMethod(method);

    // We are only interested in getters and setters
    if (!sm.getName().startsWith("get") && !sm.getName().startsWith("set"))
      return Type.NOT_SUPPORTED;
    String baseName = sm.getName().substring(3);
    String getterName = "get" + baseName;
    String setterName = "set" + baseName;

    try {
      // Find the getter and the setter
      SootMethod getter =
          getSootMethod(new AndroidMethod(getterName, "", sm.getDeclaringClass().getName()));
      SootMethod setter =
          getSootMethod(new AndroidMethod(setterName, "", sm.getDeclaringClass().getName()));
      if (getter == null || setter == null) return Type.FALSE;

      if (!setter.isConcrete() || !getter.isConcrete()) return Type.NOT_SUPPORTED;

      Body bodyGetter = null;
      try {
        bodyGetter = getter.retrieveActiveBody();
      } catch (Exception ex) {
        return Type.NOT_SUPPORTED;
      }

      // Find the local that gets returned
      Local returnLocal = null;
      for (Unit u : bodyGetter.getUnits())
        if (u instanceof ReturnStmt) {
          ReturnStmt ret = (ReturnStmt) u;
          if (ret.getOp() instanceof Local) {
            returnLocal = (Local) ret.getOp();
            break;
          }
        }
      if (returnLocal == null) return Type.FALSE;

      // Find where the local is assigned a value in the code
      List<FieldRef> accessPath = new ArrayList<FieldRef>();
      Local returnBase = returnLocal;
      while (returnBase != null)
        for (Unit u : bodyGetter.getUnits()) {
          if (u instanceof AssignStmt) {
            AssignStmt assign = (AssignStmt) u;
            if (assign.getLeftOp().equals(returnBase))
              if (assign.getRightOp() instanceof InstanceFieldRef) {
                InstanceFieldRef ref = (InstanceFieldRef) assign.getRightOp();
                accessPath.add(0, ref);
                returnBase = (Local) ref.getBase();
                break;
              } else returnBase = null;
          } else if (u instanceof IdentityStmt) {
            IdentityStmt id = (IdentityStmt) u;
            if (id.getLeftOp().equals(returnBase)) returnBase = null;
          }
        }
      if (accessPath.isEmpty()) return Type.FALSE;
      /*
      // Find the corresponding access path in the setter
      for (Unit u : bodySetter.getUnits())
      	if (u instanceof AssignStmt) {
      		AssignStmt assign = (AssignStmt) u;
      		if (assign.getLeftOp() instanceof InstanceFieldRef
      				&& assign.getRightOp() instanceof Local) {
      			InstanceFieldRef iref = (InstanceFieldRef) assign.getLeftOp();
      			if (iref.getFieldRef().toString().equals(accessPath.get(accessPath.size() - 1).getFieldRef().toString())) {
      				// This is a starting point
      				boolean pathFound = false;
      				Local startLocal = (Local) iref.getBase();
      				int accessPathPos = accessPath.size() - 2;
      				while (startLocal != null) {
      					for (Unit u2 : bodySetter.getUnits()) {
      						if (u2 instanceof AssignStmt) {
      							AssignStmt assign2 = (AssignStmt) u2;
      							if (assign2.getLeftOp().equals(startLocal))
      								if (assign2.getRightOp() instanceof InstanceFieldRef) {
      									InstanceFieldRef ref = (InstanceFieldRef) assign2.getRightOp();
      									if (accessPath.get(accessPathPos--).getFieldRef().toString().equals(ref.getFieldRef().toString())) {
      										startLocal = (Local) ref.getBase();
      										break;
      									}
      									else
      										startLocal = null;
      								}
      								else
      									startLocal = null;
      						}
      						else if (u2 instanceof IdentityStmt) {
      							IdentityStmt id = (IdentityStmt) u2;
      							if (id.getLeftOp().equals(startLocal)) {
      								startLocal = null;
      								pathFound = true;
      								break;
      							}
      						}
      					}
      				}

      				if (pathFound) {
      					if (assign.getRightOp() instanceof Local) {
      						// Find the parameter being set
      						for (Unit u2 : bodySetter.getUnits())
      							if (u2 instanceof IdentityStmt) {
      								IdentityStmt id = (IdentityStmt) u2;
      								if (id.getLeftOp().equals(assign.getRightOp()))
      									return Type.TRUE;
      							}
      					}
      					break;
      				}
      			}
      		}
      	}
      return Type.FALSE;
      */
      return Type.TRUE;
    } catch (Exception ex) {
      System.err.println("Something went wrong:");
      ex.printStackTrace();
      return Type.NOT_SUPPORTED;
    }
  }