La condition signifie :
Tant que s est différent de "fin" et s est différent de "FIN"
Mais attention, tu as dis "ou", et c'est complètement différent 
Par exemple si j'écris "FIN", c'est différent de "fin", donc la première condition est vérifiée, mais ce n'est pas différent de "FIN", donc la deuxième condition n'est pas vérifiée, au final la condition entière est fausse puisqu'on a un and entre les deux première conditions (qui sont vrai ET faux) qui vaut faux, donc on sort du while 
Alors que si on a un or, et qu'on a s qui vaut "FIN", ça donnerait "vrai ou faux," puisque "FIN" est différent de "fin" (vrai) mais pas de "FIN" (faux), et" vrai ou faux" donne faux 
On aurait pas pu mettre while( s != fin) ?
Justement non, on veut vérifier que s est différent de fin et de FIN.
s étant très probablement un string dans ton exemple, il peut tout à fait valloir "fin" ou "FIN", et les majuscules font que la valeur est complètement différente 
Ensuite, on utilise les opérateur == et != sur les types primitifs (int, double, char, toussa), sur les objets (String et tout ce que tu veux), on utilise alors objet1.equals(objet2); et !objet1.equals(objet2);.
Comparer deux objets c'est bien plus compliqué que comparer deux variables avec des types primitif.
Utiliser == et =! avec un String il me semble que ça fonctionne (j'en suis pas sur, je suis tellement habitué à utiliser equals...
), mais c'est pas le cas pour tous les objets et donc c'est une mauvaise habitude à prendre 