package com.seafile.seadroid2.ui.activity; import android.os.Bundle; import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.KeyEvent; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; import com.seafile.seadroid2.R; import com.seafile.seadroid2.SettingsManager; import com.seafile.seadroid2.gesturelock.LockPatternUtils; import com.seafile.seadroid2.gesturelock.LockPatternView; import com.seafile.seadroid2.gesturelock.LockPatternView.Cell; import com.seafile.seadroid2.gesturelock.LockPatternView.DisplayMode; import java.util.ArrayList; import java.util.List; public class CreateGesturePasswordActivity extends BaseActivity implements OnClickListener, Toolbar.OnMenuItemClickListener { private static final int ID_EMPTY_MESSAGE = -1; private static final String KEY_UI_STAGE = "uiStage"; private static final String KEY_PATTERN_CHOICE = "chosenPattern"; private LockPatternView mLockPatternView; private Button mFooterRightButton; private Button mFooterLeftButton; protected TextView mHeaderText; protected List<LockPatternView.Cell> mChosenPattern = null; private Toast mToast; private Stage mUiStage = Stage.Introduction; private View mPreviewViews[][] = new View[3][3]; /** * The patten used during the help screen to show how to draw a pattern. */ private final List<LockPatternView.Cell> mAnimatePattern = new ArrayList<LockPatternView.Cell>(); @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == android.R.id.home) { setResult(RESULT_CANCELED); return true; } return super.onOptionsItemSelected(item); } @Override public boolean onMenuItemClick(MenuItem item) { return false; } /** * The states of the left footer button. */ enum LeftButtonMode { Cancel(android.R.string.cancel, true), CancelDisabled( android.R.string.cancel, false), Retry( R.string.lockpattern_retry_button_text, true), RetryDisabled( R.string.lockpattern_retry_button_text, false), Gone( ID_EMPTY_MESSAGE, false); /** * @param text * The displayed text for this mode. * @param enabled * Whether the button should be enabled. */ LeftButtonMode(int text, boolean enabled) { this.text = text; this.enabled = enabled; } final int text; final boolean enabled; } /** * The states of the right button. */ enum RightButtonMode { Continue(R.string.lockpattern_continue_button_text, true), ContinueDisabled( R.string.lockpattern_continue_button_text, false), Confirm( R.string.lockpattern_confirm_button_text, true), ConfirmDisabled( R.string.lockpattern_confirm_button_text, false), Ok( android.R.string.ok, true); /** * @param text * The displayed text for this mode. * @param enabled * Whether the button should be enabled. */ RightButtonMode(int text, boolean enabled) { this.text = text; this.enabled = enabled; } final int text; final boolean enabled; } /** * Keep track internally of where the user is in choosing a pattern. */ protected enum Stage { Introduction(R.string.lockpattern_recording_intro_header, LeftButtonMode.Cancel, RightButtonMode.ContinueDisabled, ID_EMPTY_MESSAGE, true), HelpScreen( R.string.lockpattern_settings_help_how_to_record, LeftButtonMode.Gone, RightButtonMode.Ok, ID_EMPTY_MESSAGE, false), ChoiceTooShort( R.string.lockpattern_recording_incorrect_too_short, LeftButtonMode.Retry, RightButtonMode.ContinueDisabled, ID_EMPTY_MESSAGE, true), FirstChoiceValid( R.string.lockpattern_pattern_entered_header, LeftButtonMode.Retry, RightButtonMode.Continue, ID_EMPTY_MESSAGE, false), NeedToConfirm( R.string.lockpattern_need_to_confirm, LeftButtonMode.Cancel, RightButtonMode.ConfirmDisabled, ID_EMPTY_MESSAGE, true), ConfirmWrong( R.string.lockpattern_need_to_unlock_wrong, LeftButtonMode.Cancel, RightButtonMode.ConfirmDisabled, ID_EMPTY_MESSAGE, true), ChoiceConfirmed( R.string.lockpattern_pattern_confirmed_header, LeftButtonMode.Cancel, RightButtonMode.Confirm, ID_EMPTY_MESSAGE, false); /** * @param headerMessage * The message displayed at the top. * @param leftMode * The mode of the left button. * @param rightMode * The mode of the right button. * @param footerMessage * The footer message. * @param patternEnabled * Whether the pattern widget is enabled. */ Stage(int headerMessage, LeftButtonMode leftMode, RightButtonMode rightMode, int footerMessage, boolean patternEnabled) { this.headerMessage = headerMessage; this.leftMode = leftMode; this.rightMode = rightMode; this.footerMessage = footerMessage; this.patternEnabled = patternEnabled; } final int headerMessage; final LeftButtonMode leftMode; final RightButtonMode rightMode; final int footerMessage; final boolean patternEnabled; } SettingsManager settingsMgr = SettingsManager.instance(); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.gesturepassword_create); // initialze animation mAnimatePattern.add(LockPatternView.Cell.of(0, 0)); mAnimatePattern.add(LockPatternView.Cell.of(0, 1)); mAnimatePattern.add(LockPatternView.Cell.of(1, 1)); mAnimatePattern.add(LockPatternView.Cell.of(2, 1)); mAnimatePattern.add(LockPatternView.Cell.of(2, 2)); mLockPatternView = (LockPatternView) this .findViewById(R.id.gesturepwd_create_lockview); mHeaderText = (TextView) findViewById(R.id.gesturepwd_create_text); mLockPatternView.setOnPatternListener(mChooseNewLockPatternListener); mLockPatternView.setTactileFeedbackEnabled(true); mFooterRightButton = (Button) this.findViewById(R.id.right_btn); mFooterLeftButton = (Button) this.findViewById(R.id.reset_btn); mFooterRightButton.setOnClickListener(this); mFooterLeftButton.setOnClickListener(this); initPreviewViews(); if (savedInstanceState == null) { updateStage(Stage.Introduction); updateStage(Stage.HelpScreen); } else { // restore from previous state final String patternString = savedInstanceState .getString(KEY_PATTERN_CHOICE); if (patternString != null) { mChosenPattern = LockPatternUtils .stringToPattern(patternString); } updateStage(Stage.values()[savedInstanceState.getInt(KEY_UI_STAGE)]); } Toolbar toolbar = getActionBarToolbar(); toolbar.setOnMenuItemClickListener(this); setSupportActionBar(toolbar); getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setTitle(R.string.gesture_lock); } private void initPreviewViews() { mPreviewViews = new View[3][3]; mPreviewViews[0][0] = findViewById(R.id.gesturepwd_setting_preview_0); mPreviewViews[0][1] = findViewById(R.id.gesturepwd_setting_preview_1); mPreviewViews[0][2] = findViewById(R.id.gesturepwd_setting_preview_2); mPreviewViews[1][0] = findViewById(R.id.gesturepwd_setting_preview_3); mPreviewViews[1][1] = findViewById(R.id.gesturepwd_setting_preview_4); mPreviewViews[1][2] = findViewById(R.id.gesturepwd_setting_preview_5); mPreviewViews[2][0] = findViewById(R.id.gesturepwd_setting_preview_6); mPreviewViews[2][1] = findViewById(R.id.gesturepwd_setting_preview_7); mPreviewViews[2][2] = findViewById(R.id.gesturepwd_setting_preview_8); } private void updatePreviewViews() { if (mChosenPattern == null) return; Log.i("way", "result = " + mChosenPattern.toString()); for (LockPatternView.Cell cell : mChosenPattern) { Log.i("way", "cell.getRow() = " + cell.getRow() + ", cell.getColumn() = " + cell.getColumn()); mPreviewViews[cell.getRow()][cell.getColumn()] .setBackgroundResource(R.drawable.gesture_create_grid_selected); } } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putInt(KEY_UI_STAGE, mUiStage.ordinal()); if (mChosenPattern != null) { outState.putString(KEY_PATTERN_CHOICE, LockPatternUtils.patternToString(mChosenPattern)); } } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) { if (mUiStage == Stage.HelpScreen) { updateStage(Stage.Introduction); return true; } } if (keyCode == KeyEvent.KEYCODE_MENU && mUiStage == Stage.Introduction) { updateStage(Stage.HelpScreen); return true; } return false; } private Runnable mClearPatternRunnable = new Runnable() { public void run() { mLockPatternView.clearPattern(); } }; protected LockPatternView.OnPatternListener mChooseNewLockPatternListener = new LockPatternView.OnPatternListener() { public void onPatternStart() { mLockPatternView.removeCallbacks(mClearPatternRunnable); patternInProgress(); } public void onPatternCleared() { mLockPatternView.removeCallbacks(mClearPatternRunnable); } public void onPatternDetected(List<LockPatternView.Cell> pattern) { if (pattern == null) return; // Log.i("way", "result = " + pattern.toString()); if (mUiStage == Stage.NeedToConfirm || mUiStage == Stage.ConfirmWrong) { if (mChosenPattern == null) throw new IllegalStateException( "null chosen pattern in stage 'need to confirm"); if (mChosenPattern.equals(pattern)) { updateStage(Stage.ChoiceConfirmed); } else { updateStage(Stage.ConfirmWrong); } } else if (mUiStage == Stage.Introduction || mUiStage == Stage.ChoiceTooShort) { if (pattern.size() < LockPatternUtils.MIN_LOCK_PATTERN_SIZE) { updateStage(Stage.ChoiceTooShort); } else { mChosenPattern = new ArrayList<LockPatternView.Cell>( pattern); updateStage(Stage.FirstChoiceValid); } } else { throw new IllegalStateException("Unexpected stage " + mUiStage + " when " + "entering the pattern."); } } public void onPatternCellAdded(List<Cell> pattern) { } private void patternInProgress() { mHeaderText.setText(R.string.lockpattern_recording_inprogress); mFooterLeftButton.setEnabled(false); mFooterRightButton.setEnabled(false); } }; private void updateStage(Stage stage) { mUiStage = stage; if (stage == Stage.ChoiceTooShort) { mHeaderText.setText(getResources().getString(stage.headerMessage, LockPatternUtils.MIN_LOCK_PATTERN_SIZE)); } else { mHeaderText.setText(stage.headerMessage); } if (stage.leftMode == LeftButtonMode.Gone) { mFooterLeftButton.setVisibility(View.GONE); } else { mFooterLeftButton.setVisibility(View.VISIBLE); mFooterLeftButton.setText(stage.leftMode.text); mFooterLeftButton.setEnabled(stage.leftMode.enabled); } mFooterRightButton.setText(stage.rightMode.text); mFooterRightButton.setEnabled(stage.rightMode.enabled); // same for whether the patten is enabled if (stage.patternEnabled) { mLockPatternView.enableInput(); } else { mLockPatternView.disableInput(); } mLockPatternView.setDisplayMode(DisplayMode.Correct); switch (mUiStage) { case Introduction: mLockPatternView.clearPattern(); break; case HelpScreen: mLockPatternView.setPattern(DisplayMode.Animate, mAnimatePattern); break; case ChoiceTooShort: mLockPatternView.setDisplayMode(DisplayMode.Wrong); postClearPatternRunnable(); break; case FirstChoiceValid: break; case NeedToConfirm: mLockPatternView.clearPattern(); updatePreviewViews(); break; case ConfirmWrong: mLockPatternView.setDisplayMode(DisplayMode.Wrong); postClearPatternRunnable(); break; case ChoiceConfirmed: break; } } // clear the wrong pattern unless they have started a new one // already private void postClearPatternRunnable() { mLockPatternView.removeCallbacks(mClearPatternRunnable); mLockPatternView.postDelayed(mClearPatternRunnable, 2000); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.reset_btn: if (mUiStage.leftMode == LeftButtonMode.Retry) { mChosenPattern = null; mLockPatternView.clearPattern(); updateStage(Stage.Introduction); } else if (mUiStage.leftMode == LeftButtonMode.Cancel) { // They are canceling the entire wizard setResult(RESULT_CANCELED); finish(); } else { throw new IllegalStateException( "left footer button pressed, but stage of " + mUiStage + " doesn't make sense"); } break; case R.id.right_btn: if (mUiStage.rightMode == RightButtonMode.Continue) { if (mUiStage != Stage.FirstChoiceValid) { throw new IllegalStateException("expected ui stage " + Stage.FirstChoiceValid + " when button is " + RightButtonMode.Continue); } updateStage(Stage.NeedToConfirm); } else if (mUiStage.rightMode == RightButtonMode.Confirm) { if (mUiStage != Stage.ChoiceConfirmed) { throw new IllegalStateException("expected ui stage " + Stage.ChoiceConfirmed + " when button is " + RightButtonMode.Confirm); } saveChosenPatternAndFinish(); } else if (mUiStage.rightMode == RightButtonMode.Ok) { if (mUiStage != Stage.HelpScreen) { throw new IllegalStateException( "Help screen is only mode with ok button, but " + "stage is " + mUiStage); } mLockPatternView.clearPattern(); mLockPatternView.setDisplayMode(DisplayMode.Correct); updateStage(Stage.Introduction); } break; } } private void saveChosenPatternAndFinish() { LockPatternUtils mLockPatternUtils = new LockPatternUtils(this); mLockPatternUtils.saveLockPattern(mChosenPattern); settingsMgr.setupGestureLock(); showShortToast(this, getResources().getString(R.string.lockpattern_pattern_toast_saved)); setResult(RESULT_OK); finish(); } }