仿写Android屏幕解锁小应用

近日需要设置密码并加密,因此仿写了Android的位置和安全设置有更改屏幕锁定的设置。先看效果图:

点击后,第一次是可设置密码。

设置成功密码后再点Button按钮将会出现:


由于时间紧,因此只研究了字母和数字设置的密码。


思路分析如下:

将密码加密后放置到一个文件里,如果读了来为空则认为没有设置密码,这样,你需要先设置密码,若不为空,则是要确认密码。因此需要一个设置密码的类ChooseMasterLockPassword,一个确认密码的类ConfirmMasterLockPassword,还有一个帮助类ChooseMasterLockSettingsHelper,和一个工具类LockPatternUtils(Android原来将这个类是放置在/frameworks/base/core/java/com/android/internal/widget下,我对它进行了改写,因为它原来是将数据保存到/data/system下面,权限不够的话就没法访问,并且这个类主要是为屏幕锁定服务,因此需要改写一下)。另外还有一个选择加密方式的类ChooseMasterLockGeneric,即选择密码为无还是pin加密或是密码加密。

主要代码如下:

[1] 先由Button点击进入到ChooseMasterLockGeneric:

ChooseMasterLockSettingsHelper helper = new ChooseMasterLockSettingsHelper(this);
helper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST, null, null)) 来判断是否存在密码。

[2] 再在onPreferenceTreeClick中传入参数写入点击的响应代码:

updateUnlockMethodAndFinish(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);

如:清空密码:mChooseLockSettingsHelper.utils().clearMasterLock_KP();

        设置密码:

            Intent intent = new Intent().setClass(this, ChooseMasterLockPassword.class);
            intent.putExtra(LockPatternUtils.PASSWORD_TYPE_KEY, quality);
            intent.putExtra(ChooseMasterLockPassword.PASSWORD_MIN_KEY, minLength);
            intent.putExtra(ChooseMasterLockPassword.PASSWORD_MAX_KEY, maxLength);
            intent.putExtra(CONFIRM_CREDENTIALS, false);
            intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
            startActivity(intent);

        启动到ChooseMasterLockPassword

[3]  如何保存密码:

String dataSystemDirectory = "/data/data/com.android.lock/";
// Added by Hao Jingjing at 2011-12-21
sLockMasterPasswordFilename_KP = dataSystemDirectory + LOCK_MASTERPASSWORD_FILE_KP;

通过:

    public void saveMasterLockPassword_KP(String password) {
        // Compute the hash
        final byte[] hash = passwordToHash(password);
        try {
            // Write the hash to file
            RandomAccessFile raf = new RandomAccessFile(sLockMasterPasswordFilename_KP, "rw");
            // Truncate the file if pattern is null, to clear the lock
            if (password == null) {
                raf.setLength(0);
            } else {
                raf.write(hash, 0, hash.length);
            }
            raf.close();
        } catch (FileNotFoundException fnfe) {
            // Cant do much, unless we want to fail over to using the settings provider
            Log.e(TAG, "Unable to save lock pattern to " + sLockMasterPasswordFilename_KP);
        } catch (IOException ioe) {
            // Cant do much
            Log.e(TAG, "Unable to save lock pattern to " + sLockMasterPasswordFilename_KP);
        }
    }

进行保存。



列出主要代码如下:

src:

ChooseMasterLockGeneric.java:

/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.lock;

//import com.android.internal.widget.LockPatternUtils;

import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceCategory;
import android.preference.PreferenceScreen;

public class ChooseMasterLockGeneric extends PreferenceActivity {
    private static final int MIN_PASSWORD_LENGTH = 4;
    private static final String KEY_UNLOCK_SET_NONE = "unlock_set_none";
    private static final String KEY_UNLOCK_SET_PIN = "unlock_set_pin";
    private static final String KEY_UNLOCK_SET_PASSWORD = "unlock_set_password";
    private static final String KEY_UNLOCK_SET_PATTERN = "unlock_set_pattern";
    private static final int CONFIRM_EXISTING_REQUEST = 100;
    private static final String PASSWORD_CONFIRMED = "password_confirmed";
    private static final String CONFIRM_CREDENTIALS = "confirm_credentials";

    private ChooseMasterLockSettingsHelper mChooseLockSettingsHelper;
    private DevicePolicyManager mDPM;
    private boolean mPasswordConfirmed = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
        mChooseLockSettingsHelper = new ChooseMasterLockSettingsHelper(this);

        if (savedInstanceState != null) {
            mPasswordConfirmed = savedInstanceState.getBoolean(PASSWORD_CONFIRMED);
        }

        if (!mPasswordConfirmed) {
            ChooseMasterLockSettingsHelper helper = new ChooseMasterLockSettingsHelper(this);
            if (!helper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST, null, null)) {
                mPasswordConfirmed = true; // no password set, so no need to confirm
                updatePreferencesOrFinish();
            }
        } else {
            updatePreferencesOrFinish();
        }
    }

    @Override
    public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
            Preference preference) {
        final String key = preference.getKey();
        boolean handled = true;
        if (KEY_UNLOCK_SET_NONE.equals(key)) {
            updateUnlockMethodAndFinish(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
        } else if (KEY_UNLOCK_SET_PATTERN.equals(key)) {
            updateUnlockMethodAndFinish(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
        } else if (KEY_UNLOCK_SET_PIN.equals(key)) {
            updateUnlockMethodAndFinish(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC);
        } else if (KEY_UNLOCK_SET_PASSWORD.equals(key)) {
            updateUnlockMethodAndFinish(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC);
        } else {
            handled = false;
        }
        return handled;
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == CONFIRM_EXISTING_REQUEST && resultCode == RESULT_OK) {
            mPasswordConfirmed = true;
            updatePreferencesOrFinish();
        } else {
            setResult(RESULT_CANCELED);
            finish();
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        // Saved so we don't force user to re-enter their password if configuration changes
        outState.putBoolean(PASSWORD_CONFIRMED, mPasswordConfirmed);
    }

    private void updatePreferencesOrFinish() {
        int quality = getIntent().getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, -1);
        if (quality == -1) {
            // If caller didn't specify password quality, show the UI and allow the user to choose.
            quality = mChooseLockSettingsHelper.utils().getKeyguardStoredPasswordQuality();
            final PreferenceScreen prefScreen = getPreferenceScreen();
            if (prefScreen != null) {
                prefScreen.removeAll();
            }
            addPreferencesFromResource(R.xml.security_settings_picker);
            disableUnusablePreferences(mDPM.getPasswordQuality(null));
        } else {
            updateUnlockMethodAndFinish(quality);
        }
    }

    /***
     * Disables preferences that are less secure than required quality.
     *
     * @param quality the requested quality.
     */
    private void disableUnusablePreferences(final int quality) {
        final Preference picker = getPreferenceScreen().findPreference("security_picker_category");
        final PreferenceCategory cat = (PreferenceCategory) picker;
        final int preferenceCount = cat.getPreferenceCount();
        for (int i = 0; i < preferenceCount; i++) {
            Preference pref = cat.getPreference(i);
            if (pref instanceof PreferenceScreen) {
                final String key = ((PreferenceScreen) pref).getKey();
                boolean enabled = true;
                if (KEY_UNLOCK_SET_NONE.equals(key)) {
                    enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
                } else if (KEY_UNLOCK_SET_PATTERN.equals(key)) {
                    enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
                } else if (KEY_UNLOCK_SET_PIN.equals(key)) {
                    enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
                } else if (KEY_UNLOCK_SET_PASSWORD.equals(key)) {
                    enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
                }
                if (!enabled) {
                    pref.setSummary(R.string.unlock_set_unlock_disabled_summary);
                    pref.setEnabled(false);
                }
            }
        }
    }

    /**
     * Invokes an activity to change the user's pattern, password or PIN based on given quality
     * and minimum quality specified by DevicePolicyManager. If quality is
     * {@link DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}, password is cleared.
     *
     * @param quality the desired quality. Ignored if DevicePolicyManager requires more security.
     */
    void updateUnlockMethodAndFinish(int quality) {
        // Sanity check. We should never get here without confirming user's existing password first.
        if (!mPasswordConfirmed) {
            throw new IllegalStateException("Tried to update password without confirming first");
        }

        // Compare minimum allowed password quality and launch appropriate security setting method
        int minQuality = mDPM.getPasswordQuality(null);
        if (quality < minQuality) {
            quality = minQuality;
        }
        if (quality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) {
            //设置密码
            int minLength = mDPM.getPasswordMinimumLength(null);
            if (minLength < MIN_PASSWORD_LENGTH) {
                minLength = MIN_PASSWORD_LENGTH;
            }
            final int maxLength = mDPM.getPasswordMaximumLength(quality);
            Intent intent = new Intent().setClass(this, ChooseMasterLockPassword.class);
            intent.putExtra(LockPatternUtils.PASSWORD_TYPE_KEY, quality);
            intent.putExtra(ChooseMasterLockPassword.PASSWORD_MIN_KEY, minLength);
            intent.putExtra(ChooseMasterLockPassword.PASSWORD_MAX_KEY, maxLength);
            intent.putExtra(CONFIRM_CREDENTIALS, false);
            intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
            startActivity(intent);
        } else if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
            //清空密码
            mChooseLockSettingsHelper.utils().clearMasterLock_KP();
            setResult(RESULT_OK);
        }
        finish();
    }
}


ChooseMasterLockPassword.java:

/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.lock;

//import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.PasswordEntryKeyboardHelper;
import com.android.internal.widget.PasswordEntryKeyboardView;

import android.app.Activity;
import android.app.admin.DevicePolicyManager;
import android.content.Intent;
import android.inputmethodservice.KeyboardView;
import android.os.Bundle;
import android.os.Handler;
import android.text.Editable;
import android.text.Selection;
import android.text.Spannable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.KeyEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.view.inputmethod.EditorInfo;
import android.widget.Button;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;


public class ChooseMasterLockPassword extends Activity implements OnClickListener, OnEditorActionListener,
        TextWatcher {
    private static final String KEY_FIRST_PIN = "first_pin";
    private static final String KEY_UI_STAGE = "ui_stage";
    private TextView mPasswordEntry;
    private int mPasswordMinLength = 4;
    private int mPasswordMaxLength = 16;
    private LockPatternUtils mLockPatternUtils;
    private int mRequestedQuality = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
    private ChooseMasterLockSettingsHelper mChooseLockSettingsHelper;
    private ChooseMasterLockPassword.Stage mUiStage = Stage.Introduction;
    private TextView mHeaderText;
    private String mFirstPin;
    private KeyboardView mKeyboardView;
    private PasswordEntryKeyboardHelper mKeyboardHelper;
    private boolean mIsAlphaMode;
    private Button mCancelButton;
    private Button mNextButton;
    public static final String PASSWORD_MIN_KEY = "lockscreen.password_min";
    public static final String PASSWORD_MAX_KEY = "lockscreen.password_max";
    private static Handler mHandler = new Handler();
    private static final int CONFIRM_EXISTING_REQUEST = 58;
    static final int RESULT_FINISHED = RESULT_FIRST_USER;
    private static final long ERROR_MESSAGE_TIMEOUT = 3000;

    /**
     * Keep track internally of where the user is in choosing a pattern.
     */
    protected enum Stage {

        Introduction(R.string.lockpassword_choose_your_password_header,
                R.string.lockpassword_choose_your_pin_header,
                R.string.lockpassword_continue_label),

        NeedToConfirm(R.string.lockpassword_confirm_your_password_header,
                R.string.lockpassword_confirm_your_pin_header,
                R.string.lockpassword_ok_label),

        ConfirmWrong(R.string.lockpassword_confirm_passwords_dont_match,
                R.string.lockpassword_confirm_pins_dont_match,
                R.string.lockpassword_continue_label);

        /**
         * @param headerMessage The message displayed at the top.
         */
        Stage(int hintInAlpha, int hintInNumeric, int nextButtonText) {
            this.alphaHint = hintInAlpha;
            this.numericHint = hintInNumeric;
            this.buttonText = nextButtonText;
        }

        public final int alphaHint;
        public final int numericHint;
        public final int buttonText;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mLockPatternUtils = new LockPatternUtils(this);
        mRequestedQuality = getIntent().getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, mRequestedQuality);
        mPasswordMinLength = getIntent().getIntExtra(PASSWORD_MIN_KEY, mPasswordMinLength);
        mPasswordMaxLength = getIntent().getIntExtra(PASSWORD_MAX_KEY, mPasswordMaxLength);

        final boolean confirmCredentials = getIntent().getBooleanExtra("confirm_credentials", true);
        int minMode = mLockPatternUtils.getRequestedPasswordQuality();
        if (mRequestedQuality < minMode) {
            mRequestedQuality = minMode;
        }
        int minLength = mLockPatternUtils.getRequestedMinimumPasswordLength();
        if (mPasswordMinLength < minLength) {
            mPasswordMinLength = minLength;
        }
        initViews();
        mChooseLockSettingsHelper = new ChooseMasterLockSettingsHelper(this);
        if (savedInstanceState == null) {
            updateStage(Stage.Introduction);
            if (confirmCredentials) {
                mChooseLockSettingsHelper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST,
                        null, null);
            }
        }
    }

    private void initViews() {
        setContentView(R.layout.choose_lock_password);
        // Disable IME on our window since we provide our own keyboard
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
                WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);

        mCancelButton = (Button) findViewById(R.id.cancel_button);
        mCancelButton.setOnClickListener(this);
        mNextButton = (Button) findViewById(R.id.next_button);
        mNextButton.setOnClickListener(this);

        mKeyboardView = (PasswordEntryKeyboardView) findViewById(R.id.keyboard);
        mPasswordEntry = (TextView) findViewById(R.id.password_entry);
        mPasswordEntry.setOnEditorActionListener(this);
        mPasswordEntry.addTextChangedListener(this);

        mIsAlphaMode = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == mRequestedQuality
            || DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC == mRequestedQuality;
        mKeyboardHelper = new PasswordEntryKeyboardHelper(this, mKeyboardView, mPasswordEntry);
        mKeyboardHelper.setKeyboardMode(mIsAlphaMode ?
                PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA
                : PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC);

        mHeaderText = (TextView) findViewById(R.id.headerText);
        mKeyboardView.requestFocus();
    }

    @Override
    protected void onResume() {
        super.onResume();
        updateStage(mUiStage);
        mKeyboardView.requestFocus();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString(KEY_UI_STAGE, mUiStage.name());
        outState.putString(KEY_FIRST_PIN, mFirstPin);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        String state = savedInstanceState.getString(KEY_UI_STAGE);
        mFirstPin = savedInstanceState.getString(KEY_FIRST_PIN);
        if (state != null) {
            mUiStage = Stage.valueOf(state);
            updateStage(mUiStage);
        }
    }

//    @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();
//                }
//                break;
//        }
//    }

    protected void updateStage(Stage stage) {
        mUiStage = stage;
        updateUi();
    }

    /**
     * Validates PIN and returns a message to display if PIN fails test.
     * @param password the raw password the user typed in
     * @return error message to show to user or null if password is OK
     */
    private String validatePassword(String password) {
        if (password.length() < mPasswordMinLength) {
            return getString(mIsAlphaMode ?
                    R.string.lockpassword_password_too_short
                    : R.string.lockpassword_pin_too_short, mPasswordMinLength);
        }
        if (password.length() > mPasswordMaxLength) {
            return getString(mIsAlphaMode ?
                    R.string.lockpassword_password_too_long
                    : R.string.lockpassword_pin_too_long, mPasswordMaxLength);
        }
        boolean hasAlpha = false;
        boolean hasDigit = false;
        boolean hasSymbol = false;
        for (int i = 0; i < password.length(); i++) {
            char c = password.charAt(i);
            // allow non white space Latin-1 characters only
            if (c <= 32 || c > 127) {
                return getString(R.string.lockpassword_illegal_character);
            }
            if (c >= '0' && c <= '9') {
                hasDigit = true;
            } else if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
                hasAlpha = true;
            } else {
                hasSymbol = true;
            }
        }
        if (DevicePolicyManager.PASSWORD_QUALITY_NUMERIC == mRequestedQuality
                && (hasAlpha | hasSymbol)) {
            // This shouldn't be possible unless user finds some way to bring up soft keyboard
            return getString(R.string.lockpassword_pin_contains_non_digits);
        } else {
            final boolean alphabetic = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
                    == mRequestedQuality;
            final boolean alphanumeric = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
                    == mRequestedQuality;
            final boolean symbolic = false; // not yet
            if ((alphabetic || alphanumeric) && !hasAlpha) {
                return getString(R.string.lockpassword_password_requires_alpha);
            }
            if (alphanumeric && !hasDigit) {
                return getString(R.string.lockpassword_password_requires_digit);
            }
            if (symbolic && !hasSymbol) {
                return getString(R.string.lockpassword_password_requires_symbol);
            }
        }
        return null;
    }

    private void handleNext() {
        final String pin = mPasswordEntry.getText().toString();
        if (TextUtils.isEmpty(pin)) {
            return;
        }
        String errorMsg = null;
        if (mUiStage == Stage.Introduction) {
            errorMsg = validatePassword(pin);
            if (errorMsg == null) {
                mFirstPin = pin;
                updateStage(Stage.NeedToConfirm);
                mPasswordEntry.setText("");
            }
        } else if (mUiStage == Stage.NeedToConfirm) {
            if (mFirstPin.equals(pin)) {
                mLockPatternUtils.clearMasterLock_KP();
                mLockPatternUtils.saveMasterLockPassword_KP(pin);
                setResult(RESULT_OK);
                finish();
            } else {
                updateStage(Stage.ConfirmWrong);
                CharSequence tmp = mPasswordEntry.getText();
                if (tmp != null) {
                    Selection.setSelection((Spannable) tmp, 0, tmp.length());
                }
            }
        }
        if (errorMsg != null) {
            showError(errorMsg, mUiStage);
        }
    }

    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.next_button:
                handleNext();
                break;

            case R.id.cancel_button:
                finish();
                break;
        }
    }

    private void showError(String msg, final Stage next) {
        mHeaderText.setText(msg);
        mHandler.postDelayed(new Runnable() {
            public void run() {
                updateStage(next);
            }
        }, ERROR_MESSAGE_TIMEOUT);
    }

    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
        // Check if this was the result of hitting the enter key
        if (actionId == EditorInfo.IME_NULL) {
            handleNext();
            return true;
        }
        return false;
    }

    /**
     * Update the hint based on current Stage and length of password entry
     */
    private void updateUi() {
        String password = mPasswordEntry.getText().toString();
        final int length = password.length();
        if (mUiStage == Stage.Introduction && length > 0) {
            if (length < mPasswordMinLength) {
                String msg = getString(mIsAlphaMode ? R.string.lockpassword_password_too_short
                        : R.string.lockpassword_pin_too_short, mPasswordMinLength);
                mHeaderText.setText(msg);
                mNextButton.setEnabled(false);
            } else {
                String error = validatePassword(password);
                if (error != null) {
                    mHeaderText.setText(error);
                    mNextButton.setEnabled(false);
                } else {
                    mHeaderText.setText(R.string.lockpassword_press_continue);
                    mNextButton.setEnabled(true);
                }
            }
        } else {
            mHeaderText.setText(mIsAlphaMode ? mUiStage.alphaHint : mUiStage.numericHint);
            mNextButton.setEnabled(length > 0);
        }
        mNextButton.setText(mUiStage.buttonText);
    }

    public void afterTextChanged(Editable s) {
        // Changing the text while error displayed resets to NeedToConfirm state
        if (mUiStage == Stage.ConfirmWrong) {
            mUiStage = Stage.NeedToConfirm;
        }
        updateUi();
    }

    public void beforeTextChanged(CharSequence s, int start, int count, int after) {

    }

    public void onTextChanged(CharSequence s, int start, int before, int count) {

    }
}

ChooseMasterLockSettingsHelper.java:

/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.lock;

import android.app.Activity;
import android.content.Intent;

//import com.android.internal.widget.LockPatternUtils;

public class ChooseMasterLockSettingsHelper {
    private LockPatternUtils mLockPatternUtils;
    private Activity mActivity;

    public ChooseMasterLockSettingsHelper(Activity activity) {
        mActivity = activity;
        mLockPatternUtils = new LockPatternUtils(activity);
    }

    public LockPatternUtils utils() {
        return mLockPatternUtils;
    }

    /**
     * If a pattern, password or PIN exists, prompt the user before allowing them to change it.
     * @param message optional message to display about the action about to be done
     * @param details optional detail message to display
     * @return true if one exists and we launched an activity to confirm it
     * @see #onActivityResult(int, int, android.content.Intent)
     */
    protected boolean launchConfirmationActivity(int request,
            CharSequence message, CharSequence details) {
        boolean launched = false;
        launched = confirmPassword(request);
        return launched;
    }

    /**
     * Launch screen to confirm the existing lock password.
     * @see #onActivityResult(int, int, android.content.Intent)
     * @return true if we launched an activity to confirm password
     */
    private boolean confirmPassword(int request) {
        if (!mLockPatternUtils.isLockMasterPasswordEnabled_KP()) return false;
        final Intent intent = new Intent();
        intent.setClassName("com.android.lock", "com.android.lock.ConfirmMasterLockPassword");
        mActivity.startActivityForResult(intent, request);
        return true;
    }


}

ConfirmMasterLockPassword.java:

/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.lock;

//import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.PasswordEntryKeyboardHelper;
import com.android.internal.widget.PasswordEntryKeyboardView;

import android.app.Activity;
import android.app.admin.DevicePolicyManager;
import android.os.Bundle;
import android.os.Handler;
import android.text.Editable;
import android.view.KeyEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.view.inputmethod.EditorInfo;
import android.widget.Button;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;

public class ConfirmMasterLockPassword extends Activity implements OnClickListener,
        OnEditorActionListener {
    private static final long ERROR_MESSAGE_TIMEOUT = 3000;
    private TextView mPasswordEntry;
    private LockPatternUtils mLockPatternUtils;
    private TextView mHeaderText;
    private Handler mHandler = new Handler();
    private PasswordEntryKeyboardHelper mKeyboardHelper;
    private PasswordEntryKeyboardView mKeyboardView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mLockPatternUtils = new LockPatternUtils(this);
        initViews();
    }

    private void initViews() {
        final int storedQuality = 131072;
        setContentView(R.layout.confirm_lock_password);
        // Disable IME on our window since we provide our own keyboard
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
                WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);

        findViewById(R.id.cancel_button).setOnClickListener(this);
        findViewById(R.id.next_button).setOnClickListener(this);
        mPasswordEntry = (TextView) findViewById(R.id.password_entry);
        mPasswordEntry.setOnEditorActionListener(this);
        mKeyboardView = (PasswordEntryKeyboardView) findViewById(R.id.keyboard);
        mHeaderText = (TextView) findViewById(R.id.headerText);
        final boolean isAlpha = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == storedQuality
                || DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC == storedQuality;
        mHeaderText.setText(isAlpha ? R.string.lockpassword_confirm_your_password_header
                : R.string.lockpassword_confirm_your_pin_header);
        mKeyboardHelper = new PasswordEntryKeyboardHelper(this, mKeyboardView, mPasswordEntry);
        mKeyboardHelper.setKeyboardMode(isAlpha ? PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA
                : PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC);
        mKeyboardView.requestFocus();
    }

    @Override
    protected void onPause() {
        super.onPause();
        mKeyboardView.requestFocus();
    }

    @Override
    protected void onResume() {
        // TODO Auto-generated method stub
        super.onResume();
        mKeyboardView.requestFocus();
    }

    private void handleNext() {
        final String pin = mPasswordEntry.getText().toString();
        if (mLockPatternUtils.checkMasterPassword_KP(pin)) {
            setResult(RESULT_OK);
            finish();
        } else {
            showError(R.string.lockpattern_need_to_unlock_wrong);
        }
    }

    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.next_button:
                handleNext();
                break;

            case R.id.cancel_button:
                setResult(RESULT_CANCELED);
                finish();
                break;
        }
    }

    private void showError(int msg) {
        mHeaderText.setText(msg);
        mPasswordEntry.setText(null);
        mHandler.postDelayed(new Runnable() {
            public void run() {
                mHeaderText.setText(R.string.lockpassword_confirm_your_password_header);
            }
        }, ERROR_MESSAGE_TIMEOUT);
    }

    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
        // Check if this was the result of hitting the enter key
        if (actionId == EditorInfo.IME_NULL) {
            handleNext();
            return true;
        }
        return false;
    }
}

LockPatternUtils.java:

/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.lock;

import android.content.ContentResolver;
import android.content.Context;
import android.os.FileObserver;
import android.security.MessageDigest;
import android.util.Log;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * Utilities for the lock patten and its settings.
 */
public class LockPatternUtils {

    private static final String TAG = "LockPatternUtils";

    private static final String SYSTEM_DIRECTORY = "/system/";
    /**
     * @hide
     * Added by Hao Jingjing at 2011-12-21
     */
    private static final String LOCK_MASTERPASSWORD_FILE_KP = "kpone_master_password.key";

    /**
     * The maximum number of incorrect attempts before the user is prevented
     * from trying again for {@link #FAILED_ATTEMPT_TIMEOUT_MS}.
     */
    public static final int FAILED_ATTEMPTS_BEFORE_TIMEOUT = 5;

    /**
     * The number of incorrect attempts before which we fall back on an alternative
     * method of verifying the user, and resetting their lock pattern.
     */
    public static final int FAILED_ATTEMPTS_BEFORE_RESET = 20;

    /**
     * How long the user is prevented from trying again after entering the
     * wrong pattern too many times.
     */
    public static final long FAILED_ATTEMPT_TIMEOUT_MS = 30000L;

    /**
     * The interval of the countdown for showing progress of the lockout.
     */
    public static final long FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS = 1000L;

    public final static String PASSWORD_TYPE_KEY = "kphone_master.password_type";
    private final static String LOCK_PASSWORD_SALT_KEY = "kphone_master.password_salt";

    private final Context mContext;
    private final ContentResolver mContentResolver;
//    private static String sLockPasswordFilename;
    
    /**
     * @hide
     * Added by Hao Jingjing at 2011-12-21
     */
    private static String sLockMasterPasswordFilename_KP;
    
    /**
     * @hide
     * Added by Hao Jingjing at 2011-12-21
     */
    private static final AtomicBoolean sMasterHaveNonZeroPasswordFile_KP = new AtomicBoolean(false);
    
    private static FileObserver sPasswordObserver;

    public LockPatternUtils(Context context) {
        mContext = context;
        mContentResolver = context.getContentResolver();

//        String dataSystemDirectory =
//                android.os.Environment.getDataDirectory().getAbsolutePath() + SYSTEM_DIRECTORY;
        String dataSystemDirectory = "/data/data/com.android.lock/";
        // Added by Hao Jingjing at 2011-12-21
        sLockMasterPasswordFilename_KP = dataSystemDirectory + LOCK_MASTERPASSWORD_FILE_KP;
        sMasterHaveNonZeroPasswordFile_KP.set(new File(sLockMasterPasswordFilename_KP).length() > 0);
        // end by hjj
        
        int fileObserverMask = FileObserver.CLOSE_WRITE | FileObserver.DELETE |
                FileObserver.MOVED_TO | FileObserver.CREATE;
        sPasswordObserver = new FileObserver(dataSystemDirectory, fileObserverMask) {
                public void onEvent(int event, String path) {
                    // Added by Hao Jingjing at 2011-12-21
                    if(LOCK_MASTERPASSWORD_FILE_KP.equals(path)){
                        sMasterHaveNonZeroPasswordFile_KP.set(new File(sLockMasterPasswordFilename_KP).length() > 0);
                    }
                    // end by hjj
                }
            };
        sPasswordObserver.startWatching();
    }

    public int getRequestedMinimumPasswordLength() {
        return 4;
    }
    
    public int getRequestedPasswordQuality() {
        return 131072;
    }

    /**
     * @hide
     * Added by Hao Jingjing at 2011-12-21
     */
    public boolean checkMasterPassword_KP(String password) {
        try {
            // Read all the bytes from the file
            RandomAccessFile raf = new RandomAccessFile(sLockMasterPasswordFilename_KP, "r");
            final byte[] stored = new byte[(int) raf.length()];
            int got = raf.read(stored, 0, stored.length);
            raf.close();
            if (got <= 0) {
                return true;
            }
            // Compare the hash from the file with the entered password's hash
            return Arrays.equals(stored, passwordToHash(password));
        } catch (FileNotFoundException fnfe) {
            return true;
        } catch (IOException ioe) {
            return true;
        }
    }
    
    /**
     * @hide
     * Added by Hao Jingjing at 2011-12-21
     */
    public boolean savedMasterPasswordExists_KP() {
        return sMasterHaveNonZeroPasswordFile_KP.get();
    }

    /**
     * @hide
     * Added by Hao Jingjing at 2011-12-21
     */
    public void saveMasterLockPassword_KP(String password) {
        // Compute the hash
        final byte[] hash = passwordToHash(password);
        try {
            // Write the hash to file
            RandomAccessFile raf = new RandomAccessFile(sLockMasterPasswordFilename_KP, "rw");
            // Truncate the file if pattern is null, to clear the lock
            if (password == null) {
                raf.setLength(0);
            } else {
                raf.write(hash, 0, hash.length);
            }
            raf.close();
        } catch (FileNotFoundException fnfe) {
            // Cant do much, unless we want to fail over to using the settings provider
            Log.e(TAG, "Unable to save lock pattern to " + sLockMasterPasswordFilename_KP);
        } catch (IOException ioe) {
            // Cant do much
            Log.e(TAG, "Unable to save lock pattern to " + sLockMasterPasswordFilename_KP);
        }
    }
    
    /**
     * @hide
     * Added by Hao Jingjing at 2011-12-21
     */
    public void clearMasterLock_KP() {
        saveMasterLockPassword_KP(null);
    }
    
    /**
     * @hide
     * Added by Hao Jingjing at 2011-12-21
     */
    public boolean isLockMasterPasswordEnabled_KP() {
        return savedMasterPasswordExists_KP();
    }
    
    /**
     * Used by device policy manager to validate the current password
     * information it has.
     */
    public int getActivePasswordQuality() {
        return 131072;
    }

    /**
     * Retrieves the quality mode we're in.
     * {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
     *
     * @return stored password quality
     */
    public int getKeyguardStoredPasswordQuality() {
        return (int) 131072;
    }

    private String getSalt() {
        long salt = getLong(LOCK_PASSWORD_SALT_KEY, 0);
        if (salt == 0) {
            try {
                salt = SecureRandom.getInstance("SHA1PRNG").nextLong();
                setLong(LOCK_PASSWORD_SALT_KEY, salt);
                Log.v(TAG, "Initialized lock password salt");
            } catch (NoSuchAlgorithmException e) {
                // Throw an exception rather than storing a password we'll never be able to recover
                throw new IllegalStateException("Couldn't get SecureRandom number", e);
            }
        }
        return Long.toHexString(salt);
    }

    /*
     * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash.
     * Not the most secure, but it is at least a second level of protection. First level is that
     * the file is in a location only readable by the system process.
     * @param password the gesture pattern.
     * @return the hash of the pattern in a byte array.
     */
     public byte[] passwordToHash(String password) {
        if (password == null) {
            return null;
        }
        String algo = null;
        byte[] hashed = null;
        try {
            byte[] saltedPassword = (password + getSalt()).getBytes();
            byte[] sha1 = MessageDigest.getInstance(algo = "SHA-1").digest(saltedPassword);
            byte[] md5 = MessageDigest.getInstance(algo = "MD5").digest(saltedPassword);
            hashed = (toHex(sha1) + toHex(md5)).getBytes();
        } catch (NoSuchAlgorithmException e) {
            Log.w(TAG, "Failed to encode string because of missing algorithm: " + algo);
        }
        return hashed;
    }

    private static String toHex(byte[] ary) {
        final String hex = "0123456789ABCDEF";
        String ret = "";
        for (int i = 0; i < ary.length; i++) {
            ret += hex.charAt((ary[i] >> 4) & 0xf);
            ret += hex.charAt(ary[i] & 0xf);
        }
        return ret;
    }

    
    private long getLong(String secureSettingKey, long def) {
        //return android.provider.Settings.Secure.getLong(mContentResolver, secureSettingKey, def);
        return android.provider.Settings.System.getLong(mContentResolver, secureSettingKey, def);
    }

    private void setLong(String secureSettingKey, long value) {
        //android.provider.Settings.Secure.putLong(mContentResolver, secureSettingKey, value);
        android.provider.Settings.System.putLong(mContentResolver, secureSettingKey, value);
    }

}


这些代码都是参考com.android.settings这个应用中的代码,相关res文件也在这个应用中。








  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值