package org.iilab.pb.trigger; import android.util.EventLog; import android.util.Log; import com.google.gson.Gson; import org.iilab.pb.common.AppConstants; import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Map; public class MultiClickEvent { private static final int TIME_INTERVAL = 8000; private static final int TIME_INTERVAL_FOR_CONFIRMATION = 3000; private static final int TOTAL_CLICKS = 4; private final int IS_STATE_CHANGE_USER_TRIGERRED = 2; private final String EVENT_LOG_TAG_POWER_SCREEN_STATE = "power_screen_state"; private Long firstEventTime; private int clickCount = 0; private int IS_POWER_STATE_ASLEEP = 0; private boolean waitForConfirmation = false; private Long vibrationStartTime; private boolean isActivated; private Map<String, String> eventLog = new HashMap<String, String>(); private boolean skipClick = false; public void reset() { firstEventTime = null; clickCount = 0; eventLog = new HashMap<String, String>(); } public void registerClick(Long eventTime) { if(waitForConfirmation){ long confirmationDuration = eventTime - vibrationStartTime; int vibrationDuration = AppConstants.HAPTIC_FEEDBACK_DURATION; boolean isConfirmationClickedBeforeVibrationEnded = confirmationDuration <= vibrationDuration; boolean isConfirmationClickedWithinTimeLimit = (vibrationDuration + TIME_INTERVAL_FOR_CONFIRMATION) >= confirmationDuration; if(isConfirmationClickedBeforeVibrationEnded){ Log.e("MultiClick", "isConfirmationClickedBeforeVibrationEnded"); skipClick = true; return; } if(!isConfirmationClickedBeforeVibrationEnded && isConfirmationClickedWithinTimeLimit){ Log.e("MultiClick", "!isConfirmationClickedBeforeVibrationEnded && isConfirmationClickedWithinTimeLimit"); isActivated = true; waitForConfirmation = false; return; } if(!isConfirmationClickedWithinTimeLimit) { Log.e("MultiClick", "!isConfirmationClickedWithinTimeLimit"); resetClickCount(eventTime); } return; } if (isFirstClick() || notWithinLimit(eventTime) || !isPowerClickBecauseOfUser()) { Log.e("MultiClick", "isFirstClick() || notWithinLimit(eventTime) || !isPowerClickBecauseOfUser()"); resetClickCount(eventTime); return; } else { clickCount++; Log.e(">>>>>>", "MultiClickEvent clickCount = " + clickCount); eventLog.put(Integer.toString(clickCount) + " click", new Date(eventTime).toString()); if (clickCount >= TOTAL_CLICKS) { waitForConfirmation = true; eventLog.put("Waiting for confirmation", new Date(eventTime).toString()); vibrationStartTime = eventTime; return; } } } private void resetClickCount(Long eventTime) { firstEventTime = eventTime; clickCount = 1; waitForConfirmation=false; Log.e(">>>>>>", "MultiClickEvent Reset clickCount = " + clickCount); eventLog = new HashMap<String, String>(); eventLog.put(Integer.toString(clickCount) + " click", new Date(eventTime).toString()); } //TODO: move this to a class like PowerStateEventLogReader // - event logs can't be read post Android 4.1 private boolean isPowerClickBecauseOfUser() { ArrayList<EventLog.Event> events = new ArrayList<EventLog.Event>(); try { int powerScreenStateTagCode = EventLog.getTagCode(EVENT_LOG_TAG_POWER_SCREEN_STATE); EventLog.readEvents(new int[]{powerScreenStateTagCode}, events); if(!events.isEmpty()){ EventLog.Event event = events.get(events.size() - 1); try { Object[] powerEventLogData = (Object[]) event.getData(); if(powerEventLogData.length > 2 && (Integer)powerEventLogData[0] == IS_POWER_STATE_ASLEEP){ boolean isPowerChangeUserTriggered = (Integer) powerEventLogData[1] == IS_STATE_CHANGE_USER_TRIGERRED; Log.e(">>>>>> is Power change user triggered? ", "" + isPowerChangeUserTriggered); return isPowerChangeUserTriggered; } }catch (ClassCastException ce){ Object data = event.getData(); Log.e(">>>>>>", "could not read event data" + new Gson().toJson(data)); } } } catch (IOException e) { Log.e(">>>>>>", "could not read event logs"); } return true; } private boolean notWithinLimit(long current) { return (current - firstEventTime) > TIME_INTERVAL; } private boolean isFirstClick() { return firstEventTime == null; } public boolean isActivated() { return isActivated; } public boolean canStartVibration() { return waitForConfirmation; } public Map<String, String> getEventLog(){ return eventLog; } public boolean skipCurrentClick() { return skipClick; } public void resetSkipCurrentClickFlag() { skipClick = false; } }