gt:                     height * rect.bottom / 100.0f);
context: package org.ebookdroid.common.touch;
  
  import org.ebookdroid.common.settings.AppSettings;
  
  import android.graphics.Rect;
  import android.graphics.RectF;
  
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.HashMap;
  import java.util.LinkedList;
  import java.util.List;
  import java.util.ListIterator;
  import java.util.Map;
  
  import org.emdev.common.log.LogContext;
  import org.emdev.common.log.LogManager;
  import org.emdev.ui.actions.ActionEx;
  import org.emdev.utils.LengthUtils;
  import org.json.JSONArray;
  import org.json.JSONException;
  import org.json.JSONObject;
  
  import the.pdfviewer3.R;
  
  public class TouchManager {
  
      private static final LogContext LCTX = LogManager.root().lctx("Actions");
  
      public static final String DEFAULT_PROFILE = "DocumentView.Default";
  
      private static final Map<String, TouchProfile> profiles = new HashMap<String, TouchManager.TouchProfile>();
  
      private static final LinkedList<TouchProfile> stack = new LinkedList<TouchProfile>();
  
      public static void loadFromSettings(final AppSettings newSettings) {
          profiles.clear();
          stack.clear();
  
          boolean fromJSON = false;
          final String str = newSettings.tapProfiles;
          if (LengthUtils.isNotEmpty(str)) {
              try {
                  final List<TouchProfile> list = fromJSON(str);
                  for (final TouchProfile p : list) {
                      profiles.put(p.name, p);
                  }
              } catch (final Throwable ex) {
                  LCTX.e("Error on tap configuration load: ", ex);
              }
              fromJSON = profiles.containsKey(DEFAULT_PROFILE);
          }
  
          if (!fromJSON) {
              if (LCTX.isDebugEnabled()) {
                  LCTX.d("Creating default tap configuration...");
              }
              final TouchProfile def = addProfile(DEFAULT_PROFILE);
              {
                  final Region r = def.addRegion(0, 0, 100, 100);
                  r.setAction(Touch.DoubleTap, R.id.actions_openOptionsMenu, true);
              }
              {
                  final Region r = def.addRegion(80, 0, 100, 20);
                  r.setAction(Touch.DoubleTap, R.id.mainmenu_close, true);
              }
              {
                  final Region r = def.addRegion(0, 0, 100, 10);
                  r.setAction(Touch.SingleTap, R.id.actions_verticalConfigScrollUp, true);
              }
              {
                  final Region r = def.addRegion(0, 90, 100, 100);
                  r.setAction(Touch.SingleTap, R.id.actions_verticalConfigScrollDown, true);
              }
  
              persist();
          }
  
          stack.addFirst(profiles.get(DEFAULT_PROFILE));
      }
  
      public static void persist() {
          try {
              final JSONObject json = toJSON();
              AppSettings.updateTapProfiles(json.toString());
          } catch (final JSONException ex) {
              ex.printStackTrace();
          }
      }
  
      public static void setActionEnabled(final String profile, final int id, final boolean enabled) {
          final TouchProfile tp = profiles.get(profile);
          for (final Region r : tp.regions) {
              for (final ActionRef a : r.actions) {
                  if (a != null && a.id == id) {
                      a.enabled = enabled;
                  }
              }
          }
      }
  
      public static void setActionEnabled(final String profile, final int id, final boolean enabled, final int left,
              final int top, final int right, final int bottom) {
          final TouchProfile tp = profiles.get(profile);
          for (final Region r : tp.regions) {
              for (final ActionRef a : r.actions) {
                  if (a != null && a.id == id) {
                      a.enabled = enabled;
                      r.rect.left = left;
                      r.rect.top = top;
                      r.rect.right = right;
                      r.rect.bottom = bottom;
                      return;
                  }
              }
          }
      }
  
      public static Integer getAction(final Touch type, final float x, final float y, final float width,
              final float height) {
          return AppSettings.current().tapsEnabled ? stack.peek().getAction(type, x, y, width, height) : null;
      }
  
      public static TouchProfile addProfile(final String name) {
          final TouchProfile tp = new TouchProfile(name);
          profiles.put(tp.name, tp);
          return tp;
      }
  
      public static TouchProfile topProfile() {
          return stack.isEmpty() ? null : stack.peek();
      }
  
      public static TouchProfile pushProfile(final String name) {
          final TouchProfile prev = stack.isEmpty() ? null : stack.peek();
          final TouchProfile tp = profiles.get(name);
          if (tp != null) {
              stack.addFirst(tp);
          }
          return prev;
      }
  
      public static TouchProfile popProfile() {
          if (stack.size() > 1) {
              stack.removeFirst();
          }
          return stack.peek();
      }
  
      public static JSONObject toJSON() throws JSONException {
          final JSONObject object = new JSONObject();
          final JSONArray array = new JSONArray();
          for (final TouchProfile p : profiles.values()) {
              array.put(p.toJSON());
          }
          object.put("profiles", array);
          return object;
      }
  
      private static List<TouchProfile> fromJSON(final String str) throws JSONException {
          final List<TouchProfile> list = new ArrayList<TouchProfile>();
  
          final JSONObject root = new JSONObject(str);
  
          final JSONArray profiles = root.getJSONArray("profiles");
          for (int pIndex = 0; pIndex < profiles.length(); pIndex++) {
              final JSONObject p = profiles.getJSONObject(pIndex);
              final TouchProfile profile = TouchProfile.fromJSON(p);
              list.add(profile);
          }
          return list;
      }
  
      public static class TouchProfile {
  
          public final String name;
          final LinkedList<Region> regions = new LinkedList<Region>();
  
          public TouchProfile(final String name) {
              super();
              this.name = name;
          }
  
          public ListIterator<Region> regions(boolean forward) {
              return forward ? regions.listIterator() : regions.listIterator(regions.size());
          }
  
          public void clear() {
              regions.clear();
          }
  
          public Integer getAction(final Touch type, final float x, final float y, final float width, final float height) {
              LCTX.d("getAction(" + type + ", " + x + ", " + y + ", " + width + ", " + height + ")");
              for (final Region r : regions) {
                  final RectF rect = r.getActualRect(width, height);
                  LCTX.d("Region: " + rect);
                  if (rect.left <= x && x < rect.right && rect.top <= y && y < rect.bottom) {
                      final ActionRef action = r.getAction(type);
                      LCTX.d("Action: " + action);
                      if (action != null && action.enabled) {
                          return action.id;
                      }
                  }
              }
              return null;
          }
  
          public Region getRegion(final float x, final float y, final float width, final float height) {
              LCTX.d("getRegion(" + x + ", " + y + ", " + width + ", " + height + ")");
              for (final Region r : regions) {
                  final RectF rect = r.getActualRect(width, height);
                  LCTX.d("Region: " + rect);
                  if (rect.left <= x && x < rect.right && rect.top <= y && y < rect.bottom) {
                      return r;
                  }
              }
              return null;
          }
  
          public Region addRegion(final int left, final int top, final int right, final int bottom) {
              final Region r = new Region(new Rect(left, top, right, bottom));
              return addRegion(r);
          }
  
          public Region addRegion(final Region r) {
              regions.addFirst(r);
              return r;
          }
  
          public void removeRegion(final Region r) {
              regions.remove(r);
          }
  
          @Override
          public String toString() {
              final StringBuilder buf = new StringBuilder(this.getClass().getSimpleName());
              buf.append("[");
              buf.append("name").append("=").append(name);
              buf.append(", ");
              buf.append("regions").append("=").append(regions);
              buf.append("]");
  
              return buf.toString();
          }
  
          public JSONObject toJSON() throws JSONException {
              final JSONObject object = new JSONObject();
              object.put("name", this.name);
  
              final JSONArray array = new JSONArray();
              for (final Region r : regions) {
                  array.put(r.toJSON());
              }
              object.put("regions", array);
  
              return object;
          }
  
          public static TouchProfile fromJSON(final JSONObject json) throws JSONException {
              final TouchProfile profile = new TouchProfile(json.getString("name"));
  
              final JSONArray regions = json.getJSONArray("regions");
              for (int rIndex = 0; rIndex < regions.length(); rIndex++) {
                  final JSONObject r = regions.getJSONObject(rIndex);
                  final Region region = Region.fromJSON(r);
                  profile.regions.add(region);
              }
              return profile;
          }
      }
  
      public static enum Touch {
          SingleTap, DoubleTap, LongTap, TwoFingerTap;
      }
  
      public static class Region {
  
          private final Rect rect;
          private final ActionRef[] actions = new ActionRef[Touch.values().length];
  
          public Region(final Rect r) {
              rect = r;
          }
  
          public Region(final Region r) {
              this.rect = new Rect(r.rect);
              for (int i = 0; i < actions.length; i++) {
                  this.actions[i] = r.actions[i];
              }
          }
  
          public Rect getRect() {
              return rect;
          }
  
          public ActionRef getAction(final Touch type) {
              return actions[type.ordinal()];
          }
  
          public ActionRef setAction(final Touch type, final int id, final boolean enabled) {
              final ActionRef a = new ActionRef(type, id, enabled);
              actions[type.ordinal()] = a;
              return a;
          }
  
          public RectF getActualRect(final float width, final float height) {
              return new RectF(width * rect.left / 100.0f, height * rect.top / 100.0f, width * rect.right / 100.0f,
  