Fix 3148496: Initial pass at fragmentizing lockscreen settings.
This converts most of the existing activities to fragments and wraps them in PreferenceActivities so they can be launched as before (e.g. by a DevicePolicyManager) Upload after sync/rebase. Change-Id: I4f351b75d9fca0498bcb04b4e11ff3b70765a4ba
This commit is contained in:
@@ -22,14 +22,18 @@ import com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient;
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.internal.widget.LockPatternView;
|
||||
import com.android.internal.widget.LockPatternView.Cell;
|
||||
|
||||
import static com.android.internal.widget.LockPatternView.DisplayMode;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceActivity;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -44,7 +48,7 @@ import java.util.List;
|
||||
* - asks for confirmation / restart
|
||||
* - saves chosen password when confirmed
|
||||
*/
|
||||
public class ChooseLockPattern extends Activity implements View.OnClickListener{
|
||||
public class ChooseLockPattern extends PreferenceActivity {
|
||||
/**
|
||||
* Used by the choose lock pattern wizard to indicate the wizard is
|
||||
* finished, and each activity in the wizard should finish.
|
||||
@@ -56,440 +60,461 @@ public class ChooseLockPattern extends Activity implements View.OnClickListener{
|
||||
*/
|
||||
static final int RESULT_FINISHED = RESULT_FIRST_USER;
|
||||
|
||||
public static final int CONFIRM_EXISTING_REQUEST = 55;
|
||||
|
||||
// how long after a confirmation message is shown before moving on
|
||||
static final int INFORMATION_MSG_TIMEOUT_MS = 3000;
|
||||
|
||||
// how long we wait to clear a wrong pattern
|
||||
private static final int WRONG_PATTERN_CLEAR_TIMEOUT_MS = 2000;
|
||||
|
||||
private static final int ID_EMPTY_MESSAGE = -1;
|
||||
|
||||
protected TextView mHeaderText;
|
||||
protected LockPatternView mLockPatternView;
|
||||
protected TextView mFooterText;
|
||||
private TextView mFooterLeftButton;
|
||||
private TextView mFooterRightButton;
|
||||
protected List<LockPatternView.Cell> mChosenPattern = null;
|
||||
|
||||
/**
|
||||
* The patten used during the help screen to show how to draw a pattern.
|
||||
*/
|
||||
private final List<LockPatternView.Cell> mAnimatePattern =
|
||||
Collections.unmodifiableList(Lists.newArrayList(
|
||||
LockPatternView.Cell.of(0, 0),
|
||||
LockPatternView.Cell.of(0, 1),
|
||||
LockPatternView.Cell.of(1, 1),
|
||||
LockPatternView.Cell.of(2, 1)
|
||||
));
|
||||
@Override
|
||||
public Intent getIntent() {
|
||||
Intent modIntent = new Intent(super.getIntent());
|
||||
modIntent.putExtra(EXTRA_SHOW_FRAGMENT, ChooseLockPatternFragment.class.getName());
|
||||
modIntent.putExtra(EXTRA_NO_HEADERS, true);
|
||||
return modIntent;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode,
|
||||
Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
switch (requestCode) {
|
||||
case CONFIRM_EXISTING_REQUEST:
|
||||
if (resultCode != Activity.RESULT_OK) {
|
||||
setResult(RESULT_FINISHED);
|
||||
finish();
|
||||
}
|
||||
updateStage(Stage.Introduction);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The pattern listener that responds according to a user choosing a new
|
||||
* lock pattern.
|
||||
*/
|
||||
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 (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);
|
||||
mFooterText.setText("");
|
||||
mFooterLeftButton.setEnabled(false);
|
||||
mFooterRightButton.setEnabled(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The states of the left footer button.
|
||||
*/
|
||||
enum LeftButtonMode {
|
||||
Cancel(R.string.cancel, true),
|
||||
CancelDisabled(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,
|
||||
R.string.lockpattern_recording_intro_footer, 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.CancelDisabled, 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;
|
||||
}
|
||||
|
||||
private Stage mUiStage = Stage.Introduction;
|
||||
|
||||
private Runnable mClearPatternRunnable = new Runnable() {
|
||||
public void run() {
|
||||
mLockPatternView.clearPattern();
|
||||
}
|
||||
};
|
||||
|
||||
private ChooseLockSettingsHelper mChooseLockSettingsHelper;
|
||||
|
||||
private static final String KEY_UI_STAGE = "uiStage";
|
||||
private static final String KEY_PATTERN_CHOICE = "chosenPattern";
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
// requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
super.onCreate(savedInstanceState);
|
||||
mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this);
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
|
||||
setupViews();
|
||||
|
||||
// make it so unhandled touch events within the unlock screen go to the
|
||||
// lock pattern view.
|
||||
final LinearLayoutWithDefaultTouchRecepient topLayout
|
||||
= (LinearLayoutWithDefaultTouchRecepient) findViewById(
|
||||
R.id.topLayout);
|
||||
topLayout.setDefaultTouchRecepient(mLockPatternView);
|
||||
|
||||
final boolean confirmCredentials = getIntent().getBooleanExtra("confirm_credentials", true);
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
if (confirmCredentials) {
|
||||
// first launch. As a security measure, we're in NeedToConfirm mode until we know
|
||||
// there isn't an existing password or the user confirms their password.
|
||||
updateStage(Stage.NeedToConfirm);
|
||||
boolean launchedConfirmationActivity =
|
||||
mChooseLockSettingsHelper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST,
|
||||
null, null);
|
||||
if (!launchedConfirmationActivity) {
|
||||
updateStage(Stage.Introduction);
|
||||
}
|
||||
} else {
|
||||
updateStage(Stage.Introduction);
|
||||
}
|
||||
} 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)]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep all "find view" related stuff confined to this function since in
|
||||
* case someone needs to subclass and customize.
|
||||
*/
|
||||
protected void setupViews() {
|
||||
setContentView(R.layout.choose_lock_pattern);
|
||||
|
||||
mHeaderText = (TextView) findViewById(R.id.headerText);
|
||||
|
||||
mLockPatternView = (LockPatternView) findViewById(R.id.lockPattern);
|
||||
mLockPatternView.setOnPatternListener(mChooseNewLockPatternListener);
|
||||
mLockPatternView.setTactileFeedbackEnabled(
|
||||
mChooseLockSettingsHelper.utils().isTactileFeedbackEnabled());
|
||||
|
||||
mFooterText = (TextView) findViewById(R.id.footerText);
|
||||
|
||||
mFooterLeftButton = (TextView) findViewById(R.id.footerLeftButton);
|
||||
mFooterRightButton = (TextView) findViewById(R.id.footerRightButton);
|
||||
|
||||
mFooterLeftButton.setOnClickListener(this);
|
||||
mFooterRightButton.setOnClickListener(this);
|
||||
}
|
||||
|
||||
public void onClick(View v) {
|
||||
if (v == mFooterLeftButton) {
|
||||
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_FINISHED);
|
||||
finish();
|
||||
} else {
|
||||
throw new IllegalStateException("left footer button pressed, but stage of " +
|
||||
mUiStage + " doesn't make sense");
|
||||
}
|
||||
} else if (v == mFooterRightButton) {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
// *** TODO ***
|
||||
// chooseLockPatternFragment.onKeyDown(keyCode, event);
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
public static class ChooseLockPatternFragment extends Fragment
|
||||
implements View.OnClickListener {
|
||||
|
||||
outState.putInt(KEY_UI_STAGE, mUiStage.ordinal());
|
||||
if (mChosenPattern != null) {
|
||||
outState.putString(KEY_PATTERN_CHOICE, LockPatternUtils.patternToString(mChosenPattern));
|
||||
}
|
||||
}
|
||||
public static final int CONFIRM_EXISTING_REQUEST = 55;
|
||||
|
||||
// how long after a confirmation message is shown before moving on
|
||||
static final int INFORMATION_MSG_TIMEOUT_MS = 3000;
|
||||
|
||||
/**
|
||||
* Updates the messages and buttons appropriate to what stage the user
|
||||
* is at in choosing a view. This doesn't handle clearing out the pattern;
|
||||
* the pattern is expected to be in the right state.
|
||||
* @param stage
|
||||
*/
|
||||
protected void updateStage(Stage stage) {
|
||||
// how long we wait to clear a wrong pattern
|
||||
private static final int WRONG_PATTERN_CLEAR_TIMEOUT_MS = 2000;
|
||||
|
||||
mUiStage = stage;
|
||||
private static final int ID_EMPTY_MESSAGE = -1;
|
||||
|
||||
// header text, footer text, visibility and
|
||||
// enabled state all known from the stage
|
||||
if (stage == Stage.ChoiceTooShort) {
|
||||
mHeaderText.setText(
|
||||
getResources().getString(
|
||||
stage.headerMessage,
|
||||
LockPatternUtils.MIN_LOCK_PATTERN_SIZE));
|
||||
} else {
|
||||
mHeaderText.setText(stage.headerMessage);
|
||||
}
|
||||
if (stage.footerMessage == ID_EMPTY_MESSAGE) {
|
||||
mFooterText.setText("");
|
||||
} else {
|
||||
mFooterText.setText(stage.footerMessage);
|
||||
protected TextView mHeaderText;
|
||||
protected LockPatternView mLockPatternView;
|
||||
protected TextView mFooterText;
|
||||
private TextView mFooterLeftButton;
|
||||
private TextView mFooterRightButton;
|
||||
protected List<LockPatternView.Cell> mChosenPattern = null;
|
||||
|
||||
/**
|
||||
* The patten used during the help screen to show how to draw a pattern.
|
||||
*/
|
||||
private final List<LockPatternView.Cell> mAnimatePattern =
|
||||
Collections.unmodifiableList(Lists.newArrayList(
|
||||
LockPatternView.Cell.of(0, 0),
|
||||
LockPatternView.Cell.of(0, 1),
|
||||
LockPatternView.Cell.of(1, 1),
|
||||
LockPatternView.Cell.of(2, 1)
|
||||
));
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode,
|
||||
Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
switch (requestCode) {
|
||||
case CONFIRM_EXISTING_REQUEST:
|
||||
if (resultCode != Activity.RESULT_OK) {
|
||||
getActivity().setResult(RESULT_FINISHED);
|
||||
getActivity().finish();
|
||||
}
|
||||
updateStage(Stage.Introduction);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (stage.leftMode == LeftButtonMode.Gone) {
|
||||
mFooterLeftButton.setVisibility(View.GONE);
|
||||
} else {
|
||||
mFooterLeftButton.setVisibility(View.VISIBLE);
|
||||
mFooterLeftButton.setText(stage.leftMode.text);
|
||||
mFooterLeftButton.setEnabled(stage.leftMode.enabled);
|
||||
/**
|
||||
* The pattern listener that responds according to a user choosing a new
|
||||
* lock pattern.
|
||||
*/
|
||||
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 (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);
|
||||
mFooterText.setText("");
|
||||
mFooterLeftButton.setEnabled(false);
|
||||
mFooterRightButton.setEnabled(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The states of the left footer button.
|
||||
*/
|
||||
enum LeftButtonMode {
|
||||
Cancel(R.string.cancel, true),
|
||||
CancelDisabled(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;
|
||||
}
|
||||
|
||||
mFooterRightButton.setText(stage.rightMode.text);
|
||||
mFooterRightButton.setEnabled(stage.rightMode.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);
|
||||
|
||||
// same for whether the patten is enabled
|
||||
if (stage.patternEnabled) {
|
||||
mLockPatternView.enableInput();
|
||||
} else {
|
||||
mLockPatternView.disableInput();
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
// the rest of the stuff varies enough that it is easier just to handle
|
||||
// on a case by case basis.
|
||||
mLockPatternView.setDisplayMode(DisplayMode.Correct);
|
||||
/**
|
||||
* Keep track internally of where the user is in choosing a pattern.
|
||||
*/
|
||||
protected enum Stage {
|
||||
|
||||
switch (mUiStage) {
|
||||
case Introduction:
|
||||
Introduction(
|
||||
R.string.lockpattern_recording_intro_header,
|
||||
LeftButtonMode.Cancel, RightButtonMode.ContinueDisabled,
|
||||
R.string.lockpattern_recording_intro_footer, 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.CancelDisabled, 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;
|
||||
}
|
||||
|
||||
private Stage mUiStage = Stage.Introduction;
|
||||
|
||||
private Runnable mClearPatternRunnable = new Runnable() {
|
||||
public void run() {
|
||||
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();
|
||||
break;
|
||||
case ConfirmWrong:
|
||||
mLockPatternView.setDisplayMode(DisplayMode.Wrong);
|
||||
postClearPatternRunnable();
|
||||
break;
|
||||
case ChoiceConfirmed:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private ChooseLockSettingsHelper mChooseLockSettingsHelper;
|
||||
|
||||
// clear the wrong pattern unless they have started a new one
|
||||
// already
|
||||
private void postClearPatternRunnable() {
|
||||
mLockPatternView.removeCallbacks(mClearPatternRunnable);
|
||||
mLockPatternView.postDelayed(mClearPatternRunnable, WRONG_PATTERN_CLEAR_TIMEOUT_MS);
|
||||
}
|
||||
private static final String KEY_UI_STAGE = "uiStage";
|
||||
private static final String KEY_PATTERN_CHOICE = "chosenPattern";
|
||||
|
||||
private void saveChosenPatternAndFinish() {
|
||||
LockPatternUtils utils = mChooseLockSettingsHelper.utils();
|
||||
final boolean lockVirgin = !utils.isPatternEverChosen();
|
||||
|
||||
utils.saveLockPattern(mChosenPattern);
|
||||
utils.setLockPatternEnabled(true);
|
||||
|
||||
if (lockVirgin) {
|
||||
utils.setVisiblePatternEnabled(true);
|
||||
utils.setTactileFeedbackEnabled(false);
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
mChooseLockSettingsHelper = new ChooseLockSettingsHelper(getActivity());
|
||||
}
|
||||
|
||||
setResult(RESULT_FINISHED);
|
||||
finish();
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
|
||||
// setupViews()
|
||||
View view = inflater.inflate(R.layout.choose_lock_pattern, null);
|
||||
mHeaderText = (TextView) view.findViewById(R.id.headerText);
|
||||
mLockPatternView = (LockPatternView) view.findViewById(R.id.lockPattern);
|
||||
mLockPatternView.setOnPatternListener(mChooseNewLockPatternListener);
|
||||
mLockPatternView.setTactileFeedbackEnabled(
|
||||
mChooseLockSettingsHelper.utils().isTactileFeedbackEnabled());
|
||||
|
||||
mFooterText = (TextView) view.findViewById(R.id.footerText);
|
||||
|
||||
mFooterLeftButton = (TextView) view.findViewById(R.id.footerLeftButton);
|
||||
mFooterRightButton = (TextView) view.findViewById(R.id.footerRightButton);
|
||||
|
||||
mFooterLeftButton.setOnClickListener(this);
|
||||
mFooterRightButton.setOnClickListener(this);
|
||||
|
||||
// make it so unhandled touch events within the unlock screen go to the
|
||||
// lock pattern view.
|
||||
final LinearLayoutWithDefaultTouchRecepient topLayout
|
||||
= (LinearLayoutWithDefaultTouchRecepient) view.findViewById(
|
||||
R.id.topLayout);
|
||||
topLayout.setDefaultTouchRecepient(mLockPatternView);
|
||||
|
||||
final boolean confirmCredentials = getActivity().getIntent()
|
||||
.getBooleanExtra("confirm_credentials", true);
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
if (confirmCredentials) {
|
||||
// first launch. As a security measure, we're in NeedToConfirm mode until we
|
||||
// know there isn't an existing password or the user confirms their password.
|
||||
updateStage(Stage.NeedToConfirm);
|
||||
boolean launchedConfirmationActivity =
|
||||
mChooseLockSettingsHelper.launchConfirmationActivity(
|
||||
CONFIRM_EXISTING_REQUEST, null, null);
|
||||
if (!launchedConfirmationActivity) {
|
||||
updateStage(Stage.Introduction);
|
||||
}
|
||||
} else {
|
||||
updateStage(Stage.Introduction);
|
||||
}
|
||||
} 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)]);
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
public void onClick(View v) {
|
||||
if (v == mFooterLeftButton) {
|
||||
if (mUiStage.leftMode == LeftButtonMode.Retry) {
|
||||
mChosenPattern = null;
|
||||
mLockPatternView.clearPattern();
|
||||
updateStage(Stage.Introduction);
|
||||
} else if (mUiStage.leftMode == LeftButtonMode.Cancel) {
|
||||
// They are canceling the entire wizard
|
||||
getActivity().setResult(RESULT_FINISHED);
|
||||
getActivity().finish();
|
||||
} else {
|
||||
throw new IllegalStateException("left footer button pressed, but stage of " +
|
||||
mUiStage + " doesn't make sense");
|
||||
}
|
||||
} else if (v == mFooterRightButton) {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public 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));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the messages and buttons appropriate to what stage the user
|
||||
* is at in choosing a view. This doesn't handle clearing out the pattern;
|
||||
* the pattern is expected to be in the right state.
|
||||
* @param stage
|
||||
*/
|
||||
protected void updateStage(Stage stage) {
|
||||
|
||||
mUiStage = stage;
|
||||
|
||||
// header text, footer text, visibility and
|
||||
// enabled state all known from the stage
|
||||
if (stage == Stage.ChoiceTooShort) {
|
||||
mHeaderText.setText(
|
||||
getResources().getString(
|
||||
stage.headerMessage,
|
||||
LockPatternUtils.MIN_LOCK_PATTERN_SIZE));
|
||||
} else {
|
||||
mHeaderText.setText(stage.headerMessage);
|
||||
}
|
||||
if (stage.footerMessage == ID_EMPTY_MESSAGE) {
|
||||
mFooterText.setText("");
|
||||
} else {
|
||||
mFooterText.setText(stage.footerMessage);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
// the rest of the stuff varies enough that it is easier just to handle
|
||||
// on a case by case basis.
|
||||
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();
|
||||
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, WRONG_PATTERN_CLEAR_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
private void saveChosenPatternAndFinish() {
|
||||
LockPatternUtils utils = mChooseLockSettingsHelper.utils();
|
||||
final boolean lockVirgin = !utils.isPatternEverChosen();
|
||||
|
||||
utils.saveLockPattern(mChosenPattern);
|
||||
utils.setLockPatternEnabled(true);
|
||||
|
||||
if (lockVirgin) {
|
||||
utils.setVisiblePatternEnabled(true);
|
||||
utils.setTactileFeedbackEnabled(false);
|
||||
}
|
||||
|
||||
getActivity().setResult(RESULT_FINISHED);
|
||||
getActivity().finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user