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:
@@ -651,9 +651,8 @@
|
||||
<!-- Second and third-level settings -->
|
||||
|
||||
<activity android:name="ConfirmLockPattern"/>
|
||||
<activity android:name="ConfirmLockPassword"
|
||||
android:theme="@android:style/Theme.NoTitleBar">
|
||||
</activity>
|
||||
|
||||
<activity android:name="ConfirmLockPassword"/>>
|
||||
|
||||
<activity android:name="ChooseLockGeneric">
|
||||
<intent-filter>
|
||||
@@ -669,7 +668,6 @@
|
||||
|
||||
<activity android:name="ChooseLockPassword"
|
||||
android:label="@string/lockpattern_change_lock_pin_label"
|
||||
android:theme="@android:style/Theme.NoTitleBar"
|
||||
android:exported="false">
|
||||
</activity>
|
||||
|
||||
|
109
res/layout-xlarge-land/choose_lock_password.xml
Normal file
109
res/layout-xlarge-land/choose_lock_password.xml
Normal file
@@ -0,0 +1,109 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
**
|
||||
** Copyright 2008, 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.
|
||||
*/
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center_horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<!-- "Enter PIN(Password) to unlock" -->
|
||||
<TextView android:id="@+id/headerText"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginRight="6dip"
|
||||
android:layout_marginLeft="6dip"
|
||||
android:layout_marginTop="10dip"
|
||||
android:layout_marginBottom="10dip"
|
||||
android:gravity="left"
|
||||
android:ellipsize="marquee"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
/>
|
||||
|
||||
<!-- Password entry field -->
|
||||
<EditText android:id="@+id/password_entry"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:singleLine="true"
|
||||
android:textStyle="bold"
|
||||
android:inputType="textPassword"
|
||||
android:gravity="center"
|
||||
android:layout_gravity="center"
|
||||
android:textSize="24sp"
|
||||
android:layout_marginTop="5dip"
|
||||
android:layout_marginBottom="5dip"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:background="@drawable/password_field_default"
|
||||
android:textColor="#ffffffff"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Spacer between password entry and keyboard -->
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dip"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<!-- Alphanumeric keyboard -->
|
||||
<com.android.internal.widget.PasswordEntryKeyboardView android:id="@+id/keyboard"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="#00000000"
|
||||
android:keyBackground="@*android:drawable/btn_keyboard_key_fulltrans"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dip"
|
||||
android:layout_weight="1">
|
||||
|
||||
<Button android:id="@+id/cancel_button"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="140dip"
|
||||
android:ellipsize="marquee"
|
||||
android:singleLine="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_toLeftOf="@id/next_button"
|
||||
android:text="@string/lockpassword_cancel_label"
|
||||
/>
|
||||
|
||||
<Button android:id="@+id/next_button"
|
||||
android:layout_width="140dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="marquee"
|
||||
android:singleLine="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:text="@string/lockpassword_continue_label"
|
||||
/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
82
res/layout-xlarge-land/choose_lock_pattern.xml
Normal file
82
res/layout-xlarge-land/choose_lock_pattern.xml
Normal file
@@ -0,0 +1,82 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2008 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.
|
||||
-->
|
||||
|
||||
<com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/topLayout"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<!-- left side: lock pattern -->
|
||||
<com.android.internal.widget.LockPatternView android:id="@+id/lockPattern"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<!-- right side: pattern and messages -->
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1.0">
|
||||
|
||||
<!-- header message -->
|
||||
<TextView android:id="@+id/headerText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="22sp"
|
||||
android:gravity="left"/>
|
||||
|
||||
<!-- footer message -->
|
||||
<TextView android:id="@+id/footerText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="22sp"
|
||||
android:layout_marginTop="40dip"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<!-- confirm / restart buttons -->
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dip"
|
||||
android:layout_weight="1">
|
||||
|
||||
<!-- right / bottom button: confirm or ok -->
|
||||
<Button android:id="@+id/footerRightButton"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="140dip"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:ellipsize="marquee"
|
||||
android:singleLine="true"
|
||||
android:text="@string/lockpattern_confirm_button_text"/>
|
||||
|
||||
<!-- left / top button: skip, or re-try -->
|
||||
<Button android:id="@+id/footerLeftButton"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="140dip"
|
||||
android:layout_toLeftOf="@id/footerRightButton"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:ellipsize="marquee"
|
||||
android:singleLine="true"
|
||||
android:text="@string/lockpattern_restart_button_text"/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient>
|
||||
|
108
res/layout-xlarge-land/confirm_lock_password.xml
Normal file
108
res/layout-xlarge-land/confirm_lock_password.xml
Normal file
@@ -0,0 +1,108 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
**
|
||||
** Copyright 2008, 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.
|
||||
*/
|
||||
-->
|
||||
|
||||
<!-- This is the same layout as choose_lock_password. TODO: find out why merge fails -->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center_horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<!-- "Enter PIN(Password) to unlock" -->
|
||||
<TextView android:id="@+id/headerText"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginRight="6dip"
|
||||
android:layout_marginLeft="6dip"
|
||||
android:layout_marginTop="10dip"
|
||||
android:layout_marginBottom="10dip"
|
||||
android:gravity="left"
|
||||
android:ellipsize="marquee"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
/>
|
||||
|
||||
<!-- Password entry field -->
|
||||
<EditText android:id="@+id/password_entry"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:singleLine="true"
|
||||
android:textStyle="bold"
|
||||
android:inputType="textPassword"
|
||||
android:gravity="center"
|
||||
android:layout_gravity="center"
|
||||
android:textSize="24sp"
|
||||
android:layout_marginTop="5dip"
|
||||
android:layout_marginBottom="5dip"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:background="@drawable/password_field_default"
|
||||
android:textColor="#ffffffff"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Spacer between password entry and keyboard -->
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dip"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<!-- Alphanumeric keyboard -->
|
||||
<com.android.internal.widget.PasswordEntryKeyboardView android:id="@+id/keyboard"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="#00000000"
|
||||
android:keyBackground="@*android:drawable/btn_keyboard_key_fulltrans"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:visibility="visible">
|
||||
|
||||
<Button android:id="@+id/cancel_button"
|
||||
android:layout_width="150dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="5dip"
|
||||
android:layout_toLeftOf="@id/next_button"
|
||||
android:text="@string/lockpassword_cancel_label"
|
||||
/>
|
||||
|
||||
<Button android:id="@+id/next_button"
|
||||
android:layout_width="150dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="5dip"
|
||||
android:layout_alignParentRight="true"
|
||||
android:drawableRight="@drawable/ic_btn_next"
|
||||
android:drawablePadding="10dip"
|
||||
android:text="@string/lockpassword_continue_label"
|
||||
/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
53
res/layout-xlarge-land/confirm_lock_pattern.xml
Normal file
53
res/layout-xlarge-land/confirm_lock_pattern.xml
Normal file
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2008 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.
|
||||
-->
|
||||
|
||||
<com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/topLayout"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<!-- left side: lock pattern -->
|
||||
<com.android.internal.widget.LockPatternView android:id="@+id/lockPattern"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<!-- right side: instructions and buttons -->
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1.0">
|
||||
|
||||
<!-- header message -->
|
||||
<TextView android:id="@+id/headerText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="left"
|
||||
android:textSize="22sp"/>
|
||||
|
||||
<!-- footer message -->
|
||||
<TextView android:id="@+id/footerText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="40dip"
|
||||
android:gravity="left"
|
||||
android:textSize="22sp"/>
|
||||
</LinearLayout>
|
||||
|
||||
</com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient>
|
||||
|
101
res/layout-xlarge/choose_lock_password.xml
Normal file
101
res/layout-xlarge/choose_lock_password.xml
Normal file
@@ -0,0 +1,101 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
**
|
||||
** Copyright 2008, 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.
|
||||
*/
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="@android:color/background_dark"
|
||||
android:gravity="center_horizontal">
|
||||
|
||||
<!-- header text ('Enter Pin') -->
|
||||
<TextView android:id="@+id/headerText"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:lines="2"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"/>
|
||||
|
||||
<!-- spacer above text entry field -->
|
||||
<View
|
||||
android:id="@+id/spacerBottom"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="1dip"
|
||||
android:layout_marginTop="6dip"
|
||||
android:background="@android:drawable/divider_horizontal_dark"
|
||||
/>
|
||||
|
||||
<!-- Password entry field -->
|
||||
<EditText android:id="@+id/password_entry"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:textStyle="bold"
|
||||
android:inputType="textPassword"
|
||||
android:gravity="center"
|
||||
android:layout_gravity="center"
|
||||
android:textSize="32sp"
|
||||
android:layout_marginTop="15dip"
|
||||
android:layout_marginLeft="30dip"
|
||||
android:layout_marginRight="30dip"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:background="@drawable/password_field_default"
|
||||
android:textColor="#ffffffff"
|
||||
/>
|
||||
|
||||
<!-- Spacer between password entry and keyboard -->
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dip"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<!-- Alphanumeric keyboard -->
|
||||
<com.android.internal.widget.PasswordEntryKeyboardView android:id="@+id/keyboard"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="#00000000"
|
||||
android:layout_marginBottom="30dip"
|
||||
android:keyBackground="@*android:drawable/btn_keyboard_key_fulltrans"
|
||||
/>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent">
|
||||
|
||||
<Button android:id="@+id/cancel_button"
|
||||
android:layout_width="150dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="5dip"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:text="@string/lockpassword_cancel_label"
|
||||
/>
|
||||
|
||||
<Button android:id="@+id/next_button"
|
||||
android:layout_width="150dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="5dip"
|
||||
android:layout_alignParentRight="true"
|
||||
android:drawableRight="@drawable/ic_btn_next"
|
||||
android:drawablePadding="10dip"
|
||||
android:text="@string/lockpassword_continue_label"
|
||||
/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
91
res/layout-xlarge/choose_lock_pattern.xml
Normal file
91
res/layout-xlarge/choose_lock_pattern.xml
Normal file
@@ -0,0 +1,91 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2008 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.
|
||||
-->
|
||||
<com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/topLayout"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/black">
|
||||
|
||||
<!-- takes up all space above button bar at bottom -->
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dip"
|
||||
android:layout_weight="1">
|
||||
|
||||
<TextView android:id="@+id/headerText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dip"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center"
|
||||
android:textSize="18sp"/>
|
||||
|
||||
<View
|
||||
android:background="@*android:drawable/code_lock_top"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="2dip" />
|
||||
<com.android.internal.widget.LockPatternView android:id="@+id/lockPattern"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<!-- bottom line looks bad when button bar is their too, omit in this case -->
|
||||
<!--View
|
||||
android:background="@*android:drawable/code_lock_bottom"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="8dip" /-->
|
||||
|
||||
<TextView android:id="@+id/footerText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dip"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center"
|
||||
android:textSize="14sp"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<LinearLayout style="@android:style/ButtonBar"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<Button android:id="@+id/footerLeftButton"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="140dip"
|
||||
android:ellipsize="marquee"
|
||||
android:singleLine="true"
|
||||
android:text="@string/lockpattern_restart_button_text"/>
|
||||
|
||||
<View
|
||||
android:visibility="invisible"
|
||||
android:layout_height="0dip"
|
||||
android:layout_width="1dip"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<Button android:id="@+id/footerRightButton"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="140dip"
|
||||
android:ellipsize="marquee"
|
||||
android:singleLine="true"
|
||||
android:drawableRight="@drawable/ic_btn_next"
|
||||
android:drawablePadding="3dip"
|
||||
android:text="@string/lockpattern_confirm_button_text"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient>
|
105
res/layout-xlarge/confirm_lock_password.xml
Normal file
105
res/layout-xlarge/confirm_lock_password.xml
Normal file
@@ -0,0 +1,105 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
**
|
||||
** Copyright 2008, 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.
|
||||
*/
|
||||
-->
|
||||
|
||||
<!-- This is the same layout as choose_lock_password -->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="@android:color/background_dark"
|
||||
android:gravity="center_horizontal">
|
||||
|
||||
<!-- header text ('Enter Pin') -->
|
||||
<TextView android:id="@+id/headerText"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:lines="2"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"/>
|
||||
|
||||
<!-- spacer above text entry field -->
|
||||
<View
|
||||
android:id="@+id/spacerBottom"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="1dip"
|
||||
android:layout_marginTop="6dip"
|
||||
android:background="@android:drawable/divider_horizontal_dark"
|
||||
/>
|
||||
|
||||
<!-- Password entry field -->
|
||||
<EditText android:id="@+id/password_entry"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:textStyle="bold"
|
||||
android:inputType="textPassword"
|
||||
android:gravity="center"
|
||||
android:layout_gravity="center"
|
||||
android:textSize="32sp"
|
||||
android:layout_marginTop="15dip"
|
||||
android:layout_marginLeft="30dip"
|
||||
android:layout_marginRight="30dip"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:background="@drawable/password_field_default"
|
||||
android:textColor="#ffffffff"
|
||||
/>
|
||||
|
||||
<!-- Spacer between password entry and keyboard -->
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dip"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<!-- Alphanumeric keyboard -->
|
||||
<com.android.internal.widget.PasswordEntryKeyboardView android:id="@+id/keyboard"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="#00000000"
|
||||
android:layout_marginBottom="30dip"
|
||||
android:keyBackground="@*android:drawable/btn_keyboard_key_fulltrans"
|
||||
/>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent">
|
||||
|
||||
<Button android:id="@+id/cancel_button"
|
||||
android:layout_width="150dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="5dip"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:text="@string/lockpassword_cancel_label"
|
||||
/>
|
||||
|
||||
<Button android:id="@+id/next_button"
|
||||
android:layout_width="150dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="5dip"
|
||||
android:layout_alignParentRight="true"
|
||||
android:drawableRight="@drawable/ic_btn_next"
|
||||
android:drawablePadding="10dip"
|
||||
android:text="@string/lockpassword_continue_label"
|
||||
/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
51
res/layout-xlarge/confirm_lock_pattern.xml
Normal file
51
res/layout-xlarge/confirm_lock_pattern.xml
Normal file
@@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2008 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.
|
||||
-->
|
||||
<com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/topLayout"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/black">
|
||||
|
||||
<TextView android:id="@+id/headerText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dip"
|
||||
android:layout_weight="1.0"
|
||||
android:gravity="center"
|
||||
android:textSize="18sp"/>
|
||||
|
||||
<View
|
||||
android:background="@*android:drawable/code_lock_top"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="2dip" />
|
||||
<com.android.internal.widget.LockPatternView android:id="@+id/lockPattern"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<View
|
||||
android:background="@*android:drawable/code_lock_bottom"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="8dip" />
|
||||
|
||||
<TextView android:id="@+id/footerText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dip"
|
||||
android:layout_weight="1.0"
|
||||
android:gravity="center"
|
||||
android:textSize="14sp"/>
|
||||
|
||||
|
||||
</com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient>
|
@@ -18,6 +18,7 @@ package com.android.settings;
|
||||
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@@ -28,179 +29,190 @@ import android.preference.PreferenceCategory;
|
||||
import android.preference.PreferenceScreen;
|
||||
|
||||
public class ChooseLockGeneric extends PreferenceActivity {
|
||||
private static final int MIN_PASSWORD_LENGTH = 4;
|
||||
private static final String KEY_UNLOCK_SET_OFF = "unlock_set_off";
|
||||
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 ChooseLockSettingsHelper mChooseLockSettingsHelper;
|
||||
private DevicePolicyManager mDPM;
|
||||
private boolean mPasswordConfirmed = false;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
public Intent getIntent() {
|
||||
Intent modIntent = new Intent(super.getIntent());
|
||||
modIntent.putExtra(EXTRA_SHOW_FRAGMENT, ChooseLockGenericFragment.class.getName());
|
||||
modIntent.putExtra(EXTRA_NO_HEADERS, true);
|
||||
return modIntent;
|
||||
}
|
||||
|
||||
mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
|
||||
mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this);
|
||||
public static class ChooseLockGenericFragment extends SettingsPreferenceFragment {
|
||||
private static final int MIN_PASSWORD_LENGTH = 4;
|
||||
private static final String KEY_UNLOCK_SET_OFF = "unlock_set_off";
|
||||
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";
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
mPasswordConfirmed = savedInstanceState.getBoolean(PASSWORD_CONFIRMED);
|
||||
}
|
||||
private ChooseLockSettingsHelper mChooseLockSettingsHelper;
|
||||
private DevicePolicyManager mDPM;
|
||||
private boolean mPasswordConfirmed = false;
|
||||
|
||||
if (!mPasswordConfirmed) {
|
||||
ChooseLockSettingsHelper helper = new ChooseLockSettingsHelper(this);
|
||||
if (!helper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST, null, null)) {
|
||||
mPasswordConfirmed = true; // no password set, so no need to confirm
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
|
||||
mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this.getActivity());
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
mPasswordConfirmed = savedInstanceState.getBoolean(PASSWORD_CONFIRMED);
|
||||
}
|
||||
|
||||
if (!mPasswordConfirmed) {
|
||||
ChooseLockSettingsHelper helper = new ChooseLockSettingsHelper(this.getActivity(), this);
|
||||
if (!helper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST, null, null)) {
|
||||
mPasswordConfirmed = true; // no password set, so no need to confirm
|
||||
updatePreferencesOrFinish();
|
||||
}
|
||||
} else {
|
||||
updatePreferencesOrFinish();
|
||||
}
|
||||
} else {
|
||||
updatePreferencesOrFinish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
|
||||
Preference preference) {
|
||||
final String key = preference.getKey();
|
||||
boolean handled = true;
|
||||
if (KEY_UNLOCK_SET_OFF.equals(key)) {
|
||||
updateUnlockMethodAndFinish(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, true);
|
||||
} else if (KEY_UNLOCK_SET_NONE.equals(key)) {
|
||||
updateUnlockMethodAndFinish(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, false);
|
||||
} else if (KEY_UNLOCK_SET_PATTERN.equals(key)) {
|
||||
updateUnlockMethodAndFinish(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, false);
|
||||
} else if (KEY_UNLOCK_SET_PIN.equals(key)) {
|
||||
updateUnlockMethodAndFinish(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC, false);
|
||||
} else if (KEY_UNLOCK_SET_PASSWORD.equals(key)) {
|
||||
updateUnlockMethodAndFinish(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC, false);
|
||||
} else {
|
||||
handled = false;
|
||||
@Override
|
||||
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
|
||||
Preference preference) {
|
||||
final String key = preference.getKey();
|
||||
boolean handled = true;
|
||||
if (KEY_UNLOCK_SET_OFF.equals(key)) {
|
||||
updateUnlockMethodAndFinish(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, true);
|
||||
} else if (KEY_UNLOCK_SET_NONE.equals(key)) {
|
||||
updateUnlockMethodAndFinish(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, false);
|
||||
} else if (KEY_UNLOCK_SET_PATTERN.equals(key)) {
|
||||
updateUnlockMethodAndFinish(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, false);
|
||||
} else if (KEY_UNLOCK_SET_PIN.equals(key)) {
|
||||
updateUnlockMethodAndFinish(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC, false);
|
||||
} else if (KEY_UNLOCK_SET_PASSWORD.equals(key)) {
|
||||
updateUnlockMethodAndFinish(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC, false);
|
||||
} else {
|
||||
handled = false;
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
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);
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (requestCode == CONFIRM_EXISTING_REQUEST && resultCode == Activity.RESULT_OK) {
|
||||
mPasswordConfirmed = true;
|
||||
updatePreferencesOrFinish();
|
||||
} else {
|
||||
getActivity().setResult(Activity.RESULT_CANCELED);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public 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 = getActivity().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, false);
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* 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_OFF.equals(key)) {
|
||||
enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
|
||||
} else 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_COMPLEX;
|
||||
}
|
||||
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.
|
||||
* @param disabled whether or not to show LockScreen at all. Only meaningful when quality is
|
||||
* {@link DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}
|
||||
*/
|
||||
void updateUnlockMethodAndFinish(int quality, boolean disabled) {
|
||||
// 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(getActivity(), ChooseLockPassword.class);
|
||||
intent.putExtra(LockPatternUtils.PASSWORD_TYPE_KEY, quality);
|
||||
intent.putExtra(ChooseLockPassword.PASSWORD_MIN_KEY, minLength);
|
||||
intent.putExtra(ChooseLockPassword.PASSWORD_MAX_KEY, maxLength);
|
||||
intent.putExtra(CONFIRM_CREDENTIALS, false);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
|
||||
startActivity(intent);
|
||||
} else if (quality == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) {
|
||||
boolean showTutorial = !mChooseLockSettingsHelper.utils().isPatternEverChosen();
|
||||
Intent intent = new Intent();
|
||||
intent.setClass(getActivity(), showTutorial
|
||||
? ChooseLockPatternTutorial.class
|
||||
: ChooseLockPattern.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
|
||||
intent.putExtra("key_lock_method", "pattern");
|
||||
intent.putExtra(CONFIRM_CREDENTIALS, false);
|
||||
startActivity(intent);
|
||||
} else if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
|
||||
mChooseLockSettingsHelper.utils().clearLock();
|
||||
mChooseLockSettingsHelper.utils().setLockScreenDisabled(disabled);
|
||||
getActivity().setResult(Activity.RESULT_OK);
|
||||
}
|
||||
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, false);
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* 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_OFF.equals(key)) {
|
||||
enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
|
||||
} else 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_COMPLEX;
|
||||
}
|
||||
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.
|
||||
* @param disabled whether or not to show LockScreen at all. Only meaningful when quality is
|
||||
* {@link DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}
|
||||
*/
|
||||
void updateUnlockMethodAndFinish(int quality, boolean disabled) {
|
||||
// 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, ChooseLockPassword.class);
|
||||
intent.putExtra(LockPatternUtils.PASSWORD_TYPE_KEY, quality);
|
||||
intent.putExtra(ChooseLockPassword.PASSWORD_MIN_KEY, minLength);
|
||||
intent.putExtra(ChooseLockPassword.PASSWORD_MAX_KEY, maxLength);
|
||||
intent.putExtra(CONFIRM_CREDENTIALS, false);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
|
||||
startActivity(intent);
|
||||
} else if (quality == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) {
|
||||
boolean showTutorial = !mChooseLockSettingsHelper.utils().isPatternEverChosen();
|
||||
Intent intent = new Intent();
|
||||
intent.setClass(this, showTutorial
|
||||
? ChooseLockPatternTutorial.class
|
||||
: ChooseLockPattern.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
|
||||
intent.putExtra("key_lock_method", "pattern");
|
||||
intent.putExtra(CONFIRM_CREDENTIALS, false);
|
||||
startActivity(intent);
|
||||
} else if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
|
||||
mChooseLockSettingsHelper.utils().clearLock();
|
||||
mChooseLockSettingsHelper.utils().setLockScreenDisabled(disabled);
|
||||
setResult(RESULT_OK);
|
||||
}
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
@@ -21,19 +21,22 @@ import com.android.internal.widget.PasswordEntryKeyboardHelper;
|
||||
import com.android.internal.widget.PasswordEntryKeyboardView;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.content.Intent;
|
||||
import android.inputmethodservice.KeyboardView;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.preference.PreferenceActivity;
|
||||
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.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.Button;
|
||||
@@ -41,30 +44,7 @@ import android.widget.TextView;
|
||||
import android.widget.TextView.OnEditorActionListener;
|
||||
|
||||
|
||||
public class ChooseLockPassword 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 int mPasswordMinLetters = 0;
|
||||
private int mPasswordMinUpperCase = 0;
|
||||
private int mPasswordMinLowerCase = 0;
|
||||
private int mPasswordMinSymbols = 0;
|
||||
private int mPasswordMinNumeric = 0;
|
||||
private int mPasswordMinNonLetter = 0;
|
||||
private LockPatternUtils mLockPatternUtils;
|
||||
private int mRequestedQuality = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
|
||||
private ChooseLockSettingsHelper mChooseLockSettingsHelper;
|
||||
private com.android.settings.ChooseLockPassword.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 class ChooseLockPassword extends PreferenceActivity {
|
||||
public static final String PASSWORD_MIN_KEY = "lockscreen.password_min";
|
||||
public static final String PASSWORD_MAX_KEY = "lockscreen.password_max";
|
||||
public static final String PASSWORD_MIN_LETTERS_KEY = "lockscreen.password_min_letters";
|
||||
@@ -73,345 +53,393 @@ public class ChooseLockPassword extends Activity implements OnClickListener, OnE
|
||||
public static final String PASSWORD_MIN_NUMERIC_KEY = "lockscreen.password_min_numeric";
|
||||
public static final String PASSWORD_MIN_SYMBOLS_KEY = "lockscreen.password_min_symbols";
|
||||
public static final String PASSWORD_MIN_NONLETTER_KEY = "lockscreen.password_min_nonletter";
|
||||
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 {
|
||||
@Override
|
||||
public Intent getIntent() {
|
||||
Intent modIntent = new Intent(super.getIntent());
|
||||
modIntent.putExtra(EXTRA_SHOW_FRAGMENT, ChooseLockPasswordFragment.class.getName());
|
||||
modIntent.putExtra(EXTRA_NO_HEADERS, true);
|
||||
return modIntent;
|
||||
}
|
||||
|
||||
Introduction(R.string.lockpassword_choose_your_password_header,
|
||||
R.string.lockpassword_choose_your_pin_header,
|
||||
R.string.lockpassword_continue_label),
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
// TODO: Fix on phones
|
||||
// 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);
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
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);
|
||||
public static class ChooseLockPasswordFragment extends Fragment
|
||||
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 int mPasswordMinLetters = 0;
|
||||
private int mPasswordMinUpperCase = 0;
|
||||
private int mPasswordMinLowerCase = 0;
|
||||
private int mPasswordMinSymbols = 0;
|
||||
private int mPasswordMinNumeric = 0;
|
||||
private int mPasswordMinNonLetter = 0;
|
||||
private LockPatternUtils mLockPatternUtils;
|
||||
private int mRequestedQuality = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
|
||||
private ChooseLockSettingsHelper mChooseLockSettingsHelper;
|
||||
private 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;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @param headerMessage The message displayed at the top.
|
||||
* Keep track internally of where the user is in choosing a pattern.
|
||||
*/
|
||||
Stage(int hintInAlpha, int hintInNumeric, int nextButtonText) {
|
||||
this.alphaHint = hintInAlpha;
|
||||
this.numericHint = hintInNumeric;
|
||||
this.buttonText = nextButtonText;
|
||||
}
|
||||
protected enum Stage {
|
||||
|
||||
public final int alphaHint;
|
||||
public final int numericHint;
|
||||
public final int buttonText;
|
||||
}
|
||||
Introduction(R.string.lockpassword_choose_your_password_header,
|
||||
R.string.lockpassword_choose_your_pin_header,
|
||||
R.string.lockpassword_continue_label),
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
mLockPatternUtils = new LockPatternUtils(this);
|
||||
mRequestedQuality = Math.max(getIntent().getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY,
|
||||
mRequestedQuality), mLockPatternUtils.getRequestedPasswordQuality());
|
||||
mPasswordMinLength = Math.max(
|
||||
getIntent().getIntExtra(PASSWORD_MIN_KEY, mPasswordMinLength), mLockPatternUtils
|
||||
.getRequestedMinimumPasswordLength());
|
||||
mPasswordMaxLength = getIntent().getIntExtra(PASSWORD_MAX_KEY, mPasswordMaxLength);
|
||||
mPasswordMinLetters = Math.max(getIntent().getIntExtra(PASSWORD_MIN_LETTERS_KEY,
|
||||
mPasswordMinLetters), mLockPatternUtils.getRequestedPasswordMinimumLetters());
|
||||
mPasswordMinUpperCase = Math.max(getIntent().getIntExtra(PASSWORD_MIN_UPPERCASE_KEY,
|
||||
mPasswordMinUpperCase), mLockPatternUtils.getRequestedPasswordMinimumUpperCase());
|
||||
mPasswordMinLowerCase = Math.max(getIntent().getIntExtra(PASSWORD_MIN_LOWERCASE_KEY,
|
||||
mPasswordMinLowerCase), mLockPatternUtils.getRequestedPasswordMinimumLowerCase());
|
||||
mPasswordMinNumeric = Math.max(getIntent().getIntExtra(PASSWORD_MIN_NUMERIC_KEY,
|
||||
mPasswordMinNumeric), mLockPatternUtils.getRequestedPasswordMinimumNumeric());
|
||||
mPasswordMinSymbols = Math.max(getIntent().getIntExtra(PASSWORD_MIN_SYMBOLS_KEY,
|
||||
mPasswordMinSymbols), mLockPatternUtils.getRequestedPasswordMinimumSymbols());
|
||||
mPasswordMinNonLetter = Math.max(getIntent().getIntExtra(PASSWORD_MIN_NONLETTER_KEY,
|
||||
mPasswordMinNonLetter), mLockPatternUtils.getRequestedPasswordMinimumNonLetter());
|
||||
final boolean confirmCredentials = getIntent().getBooleanExtra("confirm_credentials", true);
|
||||
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);
|
||||
|
||||
initViews();
|
||||
mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this);
|
||||
if (savedInstanceState == null) {
|
||||
updateStage(Stage.Introduction);
|
||||
if (confirmCredentials) {
|
||||
mChooseLockSettingsHelper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST,
|
||||
null, null);
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
// required constructor for fragments
|
||||
public ChooseLockPasswordFragment() {
|
||||
|
||||
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);
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
mLockPatternUtils = new LockPatternUtils(getActivity());
|
||||
Intent intent = getActivity().getIntent();
|
||||
mRequestedQuality = Math.max(intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY,
|
||||
mRequestedQuality), mLockPatternUtils.getRequestedPasswordQuality());
|
||||
mPasswordMinLength = Math.max(
|
||||
intent.getIntExtra(PASSWORD_MIN_KEY, mPasswordMinLength), mLockPatternUtils
|
||||
.getRequestedMinimumPasswordLength());
|
||||
mPasswordMaxLength = intent.getIntExtra(PASSWORD_MAX_KEY, mPasswordMaxLength);
|
||||
mPasswordMinLetters = Math.max(intent.getIntExtra(PASSWORD_MIN_LETTERS_KEY,
|
||||
mPasswordMinLetters), mLockPatternUtils.getRequestedPasswordMinimumLetters());
|
||||
mPasswordMinUpperCase = Math.max(intent.getIntExtra(PASSWORD_MIN_UPPERCASE_KEY,
|
||||
mPasswordMinUpperCase), mLockPatternUtils.getRequestedPasswordMinimumUpperCase());
|
||||
mPasswordMinLowerCase = Math.max(intent.getIntExtra(PASSWORD_MIN_LOWERCASE_KEY,
|
||||
mPasswordMinLowerCase), mLockPatternUtils.getRequestedPasswordMinimumLowerCase());
|
||||
mPasswordMinNumeric = Math.max(intent.getIntExtra(PASSWORD_MIN_NUMERIC_KEY,
|
||||
mPasswordMinNumeric), mLockPatternUtils.getRequestedPasswordMinimumNumeric());
|
||||
mPasswordMinSymbols = Math.max(intent.getIntExtra(PASSWORD_MIN_SYMBOLS_KEY,
|
||||
mPasswordMinSymbols), mLockPatternUtils.getRequestedPasswordMinimumSymbols());
|
||||
mPasswordMinNonLetter = Math.max(intent.getIntExtra(PASSWORD_MIN_NONLETTER_KEY,
|
||||
mPasswordMinNonLetter), mLockPatternUtils.getRequestedPasswordMinimumNonLetter());
|
||||
|
||||
mIsAlphaMode = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == mRequestedQuality
|
||||
|| DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC == mRequestedQuality
|
||||
|| DevicePolicyManager.PASSWORD_QUALITY_COMPLEX == mRequestedQuality;
|
||||
mKeyboardHelper = new PasswordEntryKeyboardHelper(this, mKeyboardView, mPasswordEntry);
|
||||
mKeyboardHelper.setKeyboardMode(mIsAlphaMode ?
|
||||
PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA
|
||||
: PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC);
|
||||
mChooseLockSettingsHelper = new ChooseLockSettingsHelper(getActivity());
|
||||
}
|
||||
|
||||
mHeaderText = (TextView) findViewById(R.id.headerText);
|
||||
mKeyboardView.requestFocus();
|
||||
}
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
updateStage(mUiStage);
|
||||
mKeyboardView.requestFocus();
|
||||
}
|
||||
View view = inflater.inflate(R.layout.choose_lock_password, null);
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putString(KEY_UI_STAGE, mUiStage.name());
|
||||
outState.putString(KEY_FIRST_PIN, mFirstPin);
|
||||
}
|
||||
mCancelButton = (Button) view.findViewById(R.id.cancel_button);
|
||||
mCancelButton.setOnClickListener(this);
|
||||
mNextButton = (Button) view.findViewById(R.id.next_button);
|
||||
mNextButton.setOnClickListener(this);
|
||||
|
||||
@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);
|
||||
mIsAlphaMode = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == mRequestedQuality
|
||||
|| DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC == mRequestedQuality
|
||||
|| DevicePolicyManager.PASSWORD_QUALITY_COMPLEX == mRequestedQuality;
|
||||
mKeyboardView = (PasswordEntryKeyboardView) view.findViewById(R.id.keyboard);
|
||||
mPasswordEntry = (TextView) view.findViewById(R.id.password_entry);
|
||||
mPasswordEntry.setOnEditorActionListener(this);
|
||||
mPasswordEntry.addTextChangedListener(this);
|
||||
|
||||
mKeyboardHelper = new PasswordEntryKeyboardHelper(getActivity(),
|
||||
mKeyboardView, mPasswordEntry);
|
||||
mKeyboardHelper.setKeyboardMode(mIsAlphaMode ?
|
||||
PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA
|
||||
: PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC);
|
||||
|
||||
mHeaderText = (TextView) view.findViewById(R.id.headerText);
|
||||
mKeyboardView.requestFocus();
|
||||
|
||||
Intent intent = getActivity().getIntent();
|
||||
final boolean confirmCredentials = intent.getBooleanExtra("confirm_credentials", true);
|
||||
if (savedInstanceState == null) {
|
||||
updateStage(Stage.Introduction);
|
||||
if (confirmCredentials) {
|
||||
mChooseLockSettingsHelper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST,
|
||||
null, null);
|
||||
}
|
||||
} else {
|
||||
mFirstPin = savedInstanceState.getString(KEY_FIRST_PIN);
|
||||
final String state = savedInstanceState.getString(KEY_UI_STAGE);
|
||||
if (state != null) {
|
||||
mUiStage = Stage.valueOf(state);
|
||||
updateStage(mUiStage);
|
||||
}
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
updateStage(mUiStage);
|
||||
mKeyboardView.requestFocus();
|
||||
}
|
||||
}
|
||||
|
||||
@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;
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putString(KEY_UI_STAGE, mUiStage.name());
|
||||
outState.putString(KEY_FIRST_PIN, mFirstPin);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
int letters = 0;
|
||||
int numbers = 0;
|
||||
int lowercase = 0;
|
||||
int symbols = 0;
|
||||
int uppercase = 0;
|
||||
int nonletter = 0;
|
||||
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') {
|
||||
numbers++;
|
||||
nonletter++;
|
||||
} else if (c >= 'A' && c <= 'Z') {
|
||||
letters++;
|
||||
uppercase++;
|
||||
} else if (c >= 'a' && c <= 'z') {
|
||||
letters++;
|
||||
lowercase++;
|
||||
} else {
|
||||
symbols++;
|
||||
nonletter++;
|
||||
@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();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (DevicePolicyManager.PASSWORD_QUALITY_NUMERIC == mRequestedQuality
|
||||
&& (letters > 0 || symbols > 0)) {
|
||||
// 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 if (DevicePolicyManager.PASSWORD_QUALITY_COMPLEX == mRequestedQuality) {
|
||||
if (letters < mPasswordMinLetters) {
|
||||
return String.format(getResources().getQuantityString(
|
||||
R.plurals.lockpassword_password_requires_letters, mPasswordMinLetters),
|
||||
mPasswordMinLetters);
|
||||
} else if (numbers < mPasswordMinNumeric) {
|
||||
return String.format(getResources().getQuantityString(
|
||||
R.plurals.lockpassword_password_requires_numeric, mPasswordMinNumeric),
|
||||
mPasswordMinNumeric);
|
||||
} else if (lowercase < mPasswordMinLowerCase) {
|
||||
return String.format(getResources().getQuantityString(
|
||||
R.plurals.lockpassword_password_requires_lowercase, mPasswordMinLowerCase),
|
||||
mPasswordMinLowerCase);
|
||||
} else if (uppercase < mPasswordMinUpperCase) {
|
||||
return String.format(getResources().getQuantityString(
|
||||
R.plurals.lockpassword_password_requires_uppercase, mPasswordMinUpperCase),
|
||||
mPasswordMinUpperCase);
|
||||
} else if (symbols < mPasswordMinSymbols) {
|
||||
return String.format(getResources().getQuantityString(
|
||||
R.plurals.lockpassword_password_requires_symbols, mPasswordMinSymbols),
|
||||
mPasswordMinSymbols);
|
||||
} else if (nonletter < mPasswordMinNonLetter) {
|
||||
return String.format(getResources().getQuantityString(
|
||||
R.plurals.lockpassword_password_requires_nonletter, mPasswordMinNonLetter),
|
||||
mPasswordMinNonLetter);
|
||||
}
|
||||
} else {
|
||||
final boolean alphabetic = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
|
||||
== mRequestedQuality;
|
||||
final boolean alphanumeric = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
|
||||
== mRequestedQuality;
|
||||
if ((alphabetic || alphanumeric) && letters == 0) {
|
||||
return getString(R.string.lockpassword_password_requires_alpha);
|
||||
}
|
||||
if (alphanumeric && numbers == 0) {
|
||||
return getString(R.string.lockpassword_password_requires_digit);
|
||||
}
|
||||
}
|
||||
if(mLockPatternUtils.checkPasswordHistory(password)) {
|
||||
return getString(mIsAlphaMode ? R.string.lockpassword_password_recently_used
|
||||
: R.string.lockpassword_pin_recently_used);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void handleNext() {
|
||||
final String pin = mPasswordEntry.getText().toString();
|
||||
if (TextUtils.isEmpty(pin)) {
|
||||
return;
|
||||
protected void updateStage(Stage stage) {
|
||||
mUiStage = stage;
|
||||
updateUi();
|
||||
}
|
||||
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.clearLock();
|
||||
mLockPatternUtils.saveLockPassword(pin, mRequestedQuality);
|
||||
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 && event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||
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
|
||||
/**
|
||||
* 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);
|
||||
mHeaderText.setText(msg);
|
||||
mNextButton.setEnabled(false);
|
||||
}
|
||||
if (password.length() > mPasswordMaxLength) {
|
||||
return getString(mIsAlphaMode ?
|
||||
R.string.lockpassword_password_too_long
|
||||
: R.string.lockpassword_pin_too_long, mPasswordMaxLength);
|
||||
}
|
||||
int letters = 0;
|
||||
int numbers = 0;
|
||||
int lowercase = 0;
|
||||
int symbols = 0;
|
||||
int uppercase = 0;
|
||||
int nonletter = 0;
|
||||
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') {
|
||||
numbers++;
|
||||
nonletter++;
|
||||
} else if (c >= 'A' && c <= 'Z') {
|
||||
letters++;
|
||||
uppercase++;
|
||||
} else if (c >= 'a' && c <= 'z') {
|
||||
letters++;
|
||||
lowercase++;
|
||||
} else {
|
||||
symbols++;
|
||||
nonletter++;
|
||||
}
|
||||
}
|
||||
if (DevicePolicyManager.PASSWORD_QUALITY_NUMERIC == mRequestedQuality
|
||||
&& (letters > 0 || symbols > 0)) {
|
||||
// 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 if (DevicePolicyManager.PASSWORD_QUALITY_COMPLEX == mRequestedQuality) {
|
||||
if (letters < mPasswordMinLetters) {
|
||||
return String.format(getResources().getQuantityString(
|
||||
R.plurals.lockpassword_password_requires_letters, mPasswordMinLetters),
|
||||
mPasswordMinLetters);
|
||||
} else if (numbers < mPasswordMinNumeric) {
|
||||
return String.format(getResources().getQuantityString(
|
||||
R.plurals.lockpassword_password_requires_numeric, mPasswordMinNumeric),
|
||||
mPasswordMinNumeric);
|
||||
} else if (lowercase < mPasswordMinLowerCase) {
|
||||
return String.format(getResources().getQuantityString(
|
||||
R.plurals.lockpassword_password_requires_lowercase, mPasswordMinLowerCase),
|
||||
mPasswordMinLowerCase);
|
||||
} else if (uppercase < mPasswordMinUpperCase) {
|
||||
return String.format(getResources().getQuantityString(
|
||||
R.plurals.lockpassword_password_requires_uppercase, mPasswordMinUpperCase),
|
||||
mPasswordMinUpperCase);
|
||||
} else if (symbols < mPasswordMinSymbols) {
|
||||
return String.format(getResources().getQuantityString(
|
||||
R.plurals.lockpassword_password_requires_symbols, mPasswordMinSymbols),
|
||||
mPasswordMinSymbols);
|
||||
} else if (nonletter < mPasswordMinNonLetter) {
|
||||
return String.format(getResources().getQuantityString(
|
||||
R.plurals.lockpassword_password_requires_nonletter, mPasswordMinNonLetter),
|
||||
mPasswordMinNonLetter);
|
||||
}
|
||||
} else {
|
||||
String error = validatePassword(password);
|
||||
if (error != null) {
|
||||
mHeaderText.setText(error);
|
||||
final boolean alphabetic = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
|
||||
== mRequestedQuality;
|
||||
final boolean alphanumeric = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
|
||||
== mRequestedQuality;
|
||||
if ((alphabetic || alphanumeric) && letters == 0) {
|
||||
return getString(R.string.lockpassword_password_requires_alpha);
|
||||
}
|
||||
if (alphanumeric && numbers == 0) {
|
||||
return getString(R.string.lockpassword_password_requires_digit);
|
||||
}
|
||||
}
|
||||
if(mLockPatternUtils.checkPasswordHistory(password)) {
|
||||
return getString(mIsAlphaMode ? R.string.lockpassword_password_recently_used
|
||||
: R.string.lockpassword_pin_recently_used);
|
||||
}
|
||||
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.clearLock();
|
||||
mLockPatternUtils.saveLockPassword(pin, mRequestedQuality);
|
||||
getActivity().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:
|
||||
getActivity().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 && event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||
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 {
|
||||
mHeaderText.setText(R.string.lockpassword_press_continue);
|
||||
mNextButton.setEnabled(true);
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
mHeaderText.setText(mIsAlphaMode ? mUiStage.alphaHint : mUiStage.numericHint);
|
||||
mNextButton.setEnabled(length > 0);
|
||||
mNextButton.setText(mUiStage.buttonText);
|
||||
}
|
||||
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;
|
||||
public void afterTextChanged(Editable s) {
|
||||
// Changing the text while error displayed resets to NeedToConfirm state
|
||||
if (mUiStage == Stage.ConfirmWrong) {
|
||||
mUiStage = Stage.NeedToConfirm;
|
||||
}
|
||||
updateUi();
|
||||
}
|
||||
updateUi();
|
||||
}
|
||||
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -16,83 +16,100 @@
|
||||
|
||||
package com.android.settings;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.AnimationDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.preference.PreferenceActivity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
|
||||
public class ChooseLockPatternExample extends Activity implements View.OnClickListener {
|
||||
private static final long START_DELAY = 1000;
|
||||
protected static final String TAG = "Settings";
|
||||
private View mNextButton;
|
||||
private View mSkipButton;
|
||||
private View mImageView;
|
||||
private AnimationDrawable mAnimation;
|
||||
private Handler mHandler = new Handler();
|
||||
private Runnable mRunnable = new Runnable() {
|
||||
public void run() {
|
||||
startAnimation(mAnimation);
|
||||
public class ChooseLockPatternExample extends PreferenceActivity {
|
||||
|
||||
// required constructor for fragments
|
||||
public ChooseLockPatternExample() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Intent getIntent() {
|
||||
Intent modIntent = new Intent(super.getIntent());
|
||||
modIntent.putExtra(EXTRA_SHOW_FRAGMENT, ChooseLockPatternExampleFragment.class.getName());
|
||||
modIntent.putExtra(EXTRA_NO_HEADERS, true);
|
||||
return modIntent;
|
||||
}
|
||||
|
||||
public static class ChooseLockPatternExampleFragment extends Fragment
|
||||
implements View.OnClickListener {
|
||||
private static final long START_DELAY = 1000;
|
||||
protected static final String TAG = "Settings";
|
||||
private View mNextButton;
|
||||
private View mSkipButton;
|
||||
private View mImageView;
|
||||
private AnimationDrawable mAnimation;
|
||||
private Handler mHandler = new Handler();
|
||||
private Runnable mRunnable = new Runnable() {
|
||||
public void run() {
|
||||
startAnimation(mAnimation);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.choose_lock_pattern_example, null);
|
||||
mNextButton = view.findViewById(R.id.next_button);
|
||||
mNextButton.setOnClickListener(this);
|
||||
|
||||
mSkipButton = view.findViewById(R.id.skip_button);
|
||||
mSkipButton.setOnClickListener(this);
|
||||
|
||||
mImageView = (ImageView) view.findViewById(R.id.lock_anim);
|
||||
mImageView.setBackgroundResource(R.drawable.lock_anim);
|
||||
mImageView.setOnClickListener(this);
|
||||
mAnimation = (AnimationDrawable) mImageView.getBackground();
|
||||
return view;
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.choose_lock_pattern_example);
|
||||
initViews();
|
||||
}
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
mHandler.postDelayed(mRunnable, START_DELAY);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
mHandler.postDelayed(mRunnable, START_DELAY);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
stopAnimation(mAnimation);
|
||||
}
|
||||
|
||||
public void onClick(View v) {
|
||||
if (v == mSkipButton) {
|
||||
// Canceling, so finish all
|
||||
setResult(ChooseLockPattern.RESULT_FINISHED);
|
||||
finish();
|
||||
} else if (v == mNextButton) {
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
stopAnimation(mAnimation);
|
||||
Intent intent = new Intent(this, ChooseLockPattern.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
|
||||
intent.putExtra("confirm_credentials", false);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
private void initViews() {
|
||||
mNextButton = findViewById(R.id.next_button);
|
||||
mNextButton.setOnClickListener(this);
|
||||
|
||||
mSkipButton = findViewById(R.id.skip_button);
|
||||
mSkipButton.setOnClickListener(this);
|
||||
|
||||
mImageView = (ImageView) findViewById(R.id.lock_anim);
|
||||
mImageView.setBackgroundResource(R.drawable.lock_anim);
|
||||
mImageView.setOnClickListener(this);
|
||||
mAnimation = (AnimationDrawable) mImageView.getBackground();
|
||||
}
|
||||
|
||||
protected void startAnimation(final AnimationDrawable animation) {
|
||||
if (animation != null && !animation.isRunning()) {
|
||||
animation.run();
|
||||
public void onClick(View v) {
|
||||
if (v == mSkipButton) {
|
||||
// Canceling, so finish all
|
||||
getActivity().setResult(ChooseLockPattern.RESULT_FINISHED);
|
||||
getActivity().finish();
|
||||
} else if (v == mNextButton) {
|
||||
stopAnimation(mAnimation);
|
||||
Intent intent = new Intent(getActivity(), ChooseLockPattern.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
|
||||
intent.putExtra("confirm_credentials", false);
|
||||
startActivity(intent);
|
||||
getActivity().finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void stopAnimation(final AnimationDrawable animation) {
|
||||
if (animation != null && animation.isRunning()) animation.stop();
|
||||
protected void startAnimation(final AnimationDrawable animation) {
|
||||
if (animation != null && !animation.isRunning()) {
|
||||
animation.run();
|
||||
}
|
||||
}
|
||||
|
||||
protected void stopAnimation(final AnimationDrawable animation) {
|
||||
if (animation != null && animation.isRunning()) animation.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -18,49 +18,70 @@ package com.android.settings;
|
||||
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceActivity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
public class ChooseLockPatternTutorial extends Activity implements View.OnClickListener {
|
||||
private View mNextButton;
|
||||
private View mSkipButton;
|
||||
public class ChooseLockPatternTutorial extends PreferenceActivity {
|
||||
|
||||
// required constructor for fragments
|
||||
public ChooseLockPatternTutorial() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
// Don't show the tutorial if the user has seen it before.
|
||||
LockPatternUtils lockPatternUtils = new LockPatternUtils(this);
|
||||
if (savedInstanceState == null && lockPatternUtils.isPatternEverChosen()) {
|
||||
Intent intent = new Intent(this, ChooseLockPattern.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
|
||||
intent.putExtra("confirm_credentials", false);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
} else {
|
||||
initViews();
|
||||
public Intent getIntent() {
|
||||
Intent modIntent = new Intent(super.getIntent());
|
||||
modIntent.putExtra(EXTRA_SHOW_FRAGMENT, ChooseLockPatternTutorialFragment.class.getName());
|
||||
modIntent.putExtra(EXTRA_NO_HEADERS, true);
|
||||
return modIntent;
|
||||
}
|
||||
|
||||
public static class ChooseLockPatternTutorialFragment extends Fragment
|
||||
implements View.OnClickListener {
|
||||
private View mNextButton;
|
||||
private View mSkipButton;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
// Don't show the tutorial if the user has seen it before.
|
||||
LockPatternUtils lockPatternUtils = new LockPatternUtils(getActivity());
|
||||
if (savedInstanceState == null && lockPatternUtils.isPatternEverChosen()) {
|
||||
Intent intent = new Intent(getActivity(), ChooseLockPattern.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
|
||||
intent.putExtra("confirm_credentials", false);
|
||||
startActivity(intent);
|
||||
getActivity().finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void initViews() {
|
||||
setContentView(R.layout.choose_lock_pattern_tutorial);
|
||||
mNextButton = findViewById(R.id.next_button);
|
||||
mNextButton.setOnClickListener(this);
|
||||
mSkipButton = findViewById(R.id.skip_button);
|
||||
mSkipButton.setOnClickListener(this);
|
||||
}
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.choose_lock_pattern_tutorial, null);
|
||||
mNextButton = view.findViewById(R.id.next_button);
|
||||
mNextButton.setOnClickListener(this);
|
||||
mSkipButton = view.findViewById(R.id.skip_button);
|
||||
mSkipButton.setOnClickListener(this);
|
||||
return view;
|
||||
}
|
||||
|
||||
public void onClick(View v) {
|
||||
if (v == mSkipButton) {
|
||||
// Canceling, so finish all
|
||||
setResult(ChooseLockPattern.RESULT_FINISHED);
|
||||
finish();
|
||||
} else if (v == mNextButton) {
|
||||
Intent intent = new Intent(this, ChooseLockPatternExample.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
public void onClick(View v) {
|
||||
if (v == mSkipButton) {
|
||||
// Canceling, so finish all
|
||||
getActivity().setResult(ChooseLockPattern.RESULT_FINISHED);
|
||||
getActivity().finish();
|
||||
} else if (v == mNextButton) {
|
||||
Intent intent = new Intent(getActivity(), ChooseLockPatternExample.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
|
||||
startActivity(intent);
|
||||
getActivity().finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -20,113 +20,140 @@ 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.Fragment;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.text.Editable;
|
||||
import android.preference.PreferenceActivity;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.view.ViewGroup;
|
||||
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 ConfirmLockPassword 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;
|
||||
public class ConfirmLockPassword extends PreferenceActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
mLockPatternUtils = new LockPatternUtils(this);
|
||||
initViews();
|
||||
public Intent getIntent() {
|
||||
Intent modIntent = new Intent(super.getIntent());
|
||||
modIntent.putExtra(EXTRA_SHOW_FRAGMENT, ConfirmLockPasswordFragment.class.getName());
|
||||
modIntent.putExtra(EXTRA_NO_HEADERS, true);
|
||||
return modIntent;
|
||||
}
|
||||
|
||||
private void initViews() {
|
||||
final int storedQuality = mLockPatternUtils.getKeyguardStoredPasswordQuality();
|
||||
setContentView(R.layout.confirm_lock_password);
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
// 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
|
||||
|| DevicePolicyManager.PASSWORD_QUALITY_COMPLEX == 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();
|
||||
//getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
|
||||
//WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
mKeyboardView.requestFocus();
|
||||
}
|
||||
public static class ConfirmLockPasswordFragment extends Fragment 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 onResume() {
|
||||
// TODO Auto-generated method stub
|
||||
super.onResume();
|
||||
mKeyboardView.requestFocus();
|
||||
}
|
||||
|
||||
private void handleNext() {
|
||||
final String pin = mPasswordEntry.getText().toString();
|
||||
if (mLockPatternUtils.checkPassword(pin)) {
|
||||
setResult(RESULT_OK);
|
||||
finish();
|
||||
} else {
|
||||
showError(R.string.lockpattern_need_to_unlock_wrong);
|
||||
// required constructor for fragments
|
||||
public ConfirmLockPasswordFragment() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
mLockPatternUtils = new LockPatternUtils(getActivity());
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
final int storedQuality = mLockPatternUtils.getKeyguardStoredPasswordQuality();
|
||||
View view = inflater.inflate(R.layout.confirm_lock_password, null);
|
||||
// Disable IME on our window since we provide our own keyboard
|
||||
|
||||
view.findViewById(R.id.cancel_button).setOnClickListener(this);
|
||||
view.findViewById(R.id.next_button).setOnClickListener(this);
|
||||
mPasswordEntry = (TextView) view.findViewById(R.id.password_entry);
|
||||
mPasswordEntry.setOnEditorActionListener(this);
|
||||
mKeyboardView = (PasswordEntryKeyboardView) view.findViewById(R.id.keyboard);
|
||||
mHeaderText = (TextView) view.findViewById(R.id.headerText);
|
||||
final boolean isAlpha = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == storedQuality
|
||||
|| DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC == storedQuality
|
||||
|| DevicePolicyManager.PASSWORD_QUALITY_COMPLEX == storedQuality;
|
||||
mHeaderText.setText(isAlpha ? R.string.lockpassword_confirm_your_password_header
|
||||
: R.string.lockpassword_confirm_your_pin_header);
|
||||
mKeyboardHelper = new PasswordEntryKeyboardHelper(getActivity(),
|
||||
mKeyboardView, mPasswordEntry);
|
||||
mKeyboardHelper.setKeyboardMode(isAlpha ? PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA
|
||||
: PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC);
|
||||
mKeyboardView.requestFocus();
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
mKeyboardView.requestFocus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
// TODO Auto-generated method stub
|
||||
super.onResume();
|
||||
mKeyboardView.requestFocus();
|
||||
}
|
||||
|
||||
private void handleNext() {
|
||||
final String pin = mPasswordEntry.getText().toString();
|
||||
if (mLockPatternUtils.checkPassword(pin)) {
|
||||
getActivity().setResult(RESULT_OK);
|
||||
getActivity().finish();
|
||||
} else {
|
||||
showError(R.string.lockpattern_need_to_unlock_wrong);
|
||||
}
|
||||
}, 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;
|
||||
|
||||
public void onClick(View v) {
|
||||
switch (v.getId()) {
|
||||
case R.id.next_button:
|
||||
handleNext();
|
||||
break;
|
||||
|
||||
case R.id.cancel_button:
|
||||
getActivity().setResult(RESULT_CANCELED);
|
||||
getActivity().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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -22,12 +22,16 @@ import com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient;
|
||||
import com.android.internal.widget.LockPatternView.Cell;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.content.Intent;
|
||||
import android.os.CountDownTimer;
|
||||
import android.os.SystemClock;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceActivity;
|
||||
import android.widget.TextView;
|
||||
import android.view.Window;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -37,7 +41,7 @@ import java.util.List;
|
||||
* Sets an activity result of {@link Activity#RESULT_OK} when the user
|
||||
* successfully confirmed their pattern.
|
||||
*/
|
||||
public class ConfirmLockPattern extends Activity {
|
||||
public class ConfirmLockPattern extends PreferenceActivity {
|
||||
|
||||
/**
|
||||
* Names of {@link CharSequence} fields within the originating {@link Intent}
|
||||
@@ -45,30 +49,11 @@ public class ConfirmLockPattern extends Activity {
|
||||
* The view will use the system-defined resource strings for any labels that
|
||||
* the caller does not supply.
|
||||
*/
|
||||
public static final String HEADER_TEXT = "com.android.settings.ConfirmLockPattern.header";
|
||||
public static final String FOOTER_TEXT = "com.android.settings.ConfirmLockPattern.footer";
|
||||
public static final String HEADER_WRONG_TEXT = "com.android.settings.ConfirmLockPattern.header_wrong";
|
||||
public static final String FOOTER_WRONG_TEXT = "com.android.settings.ConfirmLockPattern.footer_wrong";
|
||||
|
||||
// how long we wait to clear a wrong pattern
|
||||
private static final int WRONG_PATTERN_CLEAR_TIMEOUT_MS = 2000;
|
||||
|
||||
private static final String KEY_NUM_WRONG_ATTEMPTS = "num_wrong_attempts";
|
||||
|
||||
private LockPatternView mLockPatternView;
|
||||
private LockPatternUtils mLockPatternUtils;
|
||||
private int mNumWrongConfirmAttempts;
|
||||
private CountDownTimer mCountdownTimer;
|
||||
|
||||
private TextView mHeaderTextView;
|
||||
private TextView mFooterTextView;
|
||||
|
||||
// caller-supplied text for various prompts
|
||||
private CharSequence mHeaderText;
|
||||
private CharSequence mFooterText;
|
||||
private CharSequence mHeaderWrongText;
|
||||
private CharSequence mFooterWrongText;
|
||||
|
||||
public static final String PACKAGE = "com.android.settings";
|
||||
public static final String HEADER_TEXT = PACKAGE + ".ConfirmLockPattern.header";
|
||||
public static final String FOOTER_TEXT = PACKAGE + ".ConfirmLockPattern.footer";
|
||||
public static final String HEADER_WRONG_TEXT = PACKAGE + ".ConfirmLockPattern.header_wrong";
|
||||
public static final String FOOTER_WRONG_TEXT = PACKAGE + ".ConfirmLockPattern.footer_wrong";
|
||||
|
||||
private enum Stage {
|
||||
NeedToUnlock,
|
||||
@@ -77,194 +62,232 @@ public class ConfirmLockPattern extends Activity {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
public Intent getIntent() {
|
||||
Intent modIntent = new Intent(super.getIntent());
|
||||
modIntent.putExtra(EXTRA_SHOW_FRAGMENT, ConfirmLockPatternFragment.class.getName());
|
||||
modIntent.putExtra(EXTRA_NO_HEADERS, true);
|
||||
return modIntent;
|
||||
}
|
||||
|
||||
mLockPatternUtils = new LockPatternUtils(this);
|
||||
public static class ConfirmLockPatternFragment extends Fragment {
|
||||
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
setContentView(R.layout.confirm_lock_pattern);
|
||||
// how long we wait to clear a wrong pattern
|
||||
private static final int WRONG_PATTERN_CLEAR_TIMEOUT_MS = 2000;
|
||||
|
||||
mHeaderTextView = (TextView) findViewById(R.id.headerText);
|
||||
mLockPatternView = (LockPatternView) findViewById(R.id.lockPattern);
|
||||
mFooterTextView = (TextView) findViewById(R.id.footerText);
|
||||
private static final String KEY_NUM_WRONG_ATTEMPTS = "num_wrong_attempts";
|
||||
|
||||
// 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);
|
||||
private LockPatternView mLockPatternView;
|
||||
private LockPatternUtils mLockPatternUtils;
|
||||
private int mNumWrongConfirmAttempts;
|
||||
private CountDownTimer mCountdownTimer;
|
||||
|
||||
private TextView mHeaderTextView;
|
||||
private TextView mFooterTextView;
|
||||
|
||||
// caller-supplied text for various prompts
|
||||
private CharSequence mHeaderText;
|
||||
private CharSequence mFooterText;
|
||||
private CharSequence mHeaderWrongText;
|
||||
private CharSequence mFooterWrongText;
|
||||
|
||||
// required constructor for fragments
|
||||
public ConfirmLockPatternFragment() {
|
||||
|
||||
Intent intent = getIntent();
|
||||
if (intent != null) {
|
||||
mHeaderText = intent.getCharSequenceExtra(HEADER_TEXT);
|
||||
mFooterText = intent.getCharSequenceExtra(FOOTER_TEXT);
|
||||
mHeaderWrongText = intent.getCharSequenceExtra(HEADER_WRONG_TEXT);
|
||||
mFooterWrongText = intent.getCharSequenceExtra(FOOTER_WRONG_TEXT);
|
||||
}
|
||||
|
||||
mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled());
|
||||
mLockPatternView.setOnPatternListener(mConfirmExistingLockPatternListener);
|
||||
updateStage(Stage.NeedToUnlock);
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
mLockPatternUtils = new LockPatternUtils(getActivity());
|
||||
}
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
mNumWrongConfirmAttempts = savedInstanceState.getInt(KEY_NUM_WRONG_ATTEMPTS);
|
||||
} else {
|
||||
// on first launch, if no lock pattern is set, then finish with
|
||||
// success (don't want user to get stuck confirming something that
|
||||
// doesn't exist).
|
||||
if (!mLockPatternUtils.savedPatternExists()) {
|
||||
setResult(RESULT_OK);
|
||||
finish();
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.confirm_lock_pattern, null);
|
||||
mHeaderTextView = (TextView) view.findViewById(R.id.headerText);
|
||||
mLockPatternView = (LockPatternView) view.findViewById(R.id.lockPattern);
|
||||
mFooterTextView = (TextView) view.findViewById(R.id.footerText);
|
||||
|
||||
// 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);
|
||||
|
||||
Intent intent = getActivity().getIntent();
|
||||
if (intent != null) {
|
||||
mHeaderText = intent.getCharSequenceExtra(HEADER_TEXT);
|
||||
mFooterText = intent.getCharSequenceExtra(FOOTER_TEXT);
|
||||
mHeaderWrongText = intent.getCharSequenceExtra(HEADER_WRONG_TEXT);
|
||||
mFooterWrongText = intent.getCharSequenceExtra(FOOTER_WRONG_TEXT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
// deliberately not calling super since we are managing this in full
|
||||
outState.putInt(KEY_NUM_WRONG_ATTEMPTS, mNumWrongConfirmAttempts);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
|
||||
if (mCountdownTimer != null) {
|
||||
mCountdownTimer.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
// if the user is currently locked out, enforce it.
|
||||
long deadline = mLockPatternUtils.getLockoutAttemptDeadline();
|
||||
if (deadline != 0) {
|
||||
handleAttemptLockout(deadline);
|
||||
} else if (!mLockPatternView.isEnabled()) {
|
||||
// The deadline has passed, but the timer was cancelled...
|
||||
// Need to clean up.
|
||||
mNumWrongConfirmAttempts = 0;
|
||||
mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled());
|
||||
mLockPatternView.setOnPatternListener(mConfirmExistingLockPatternListener);
|
||||
updateStage(Stage.NeedToUnlock);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateStage(Stage stage) {
|
||||
|
||||
switch (stage) {
|
||||
case NeedToUnlock:
|
||||
if (mHeaderText != null) {
|
||||
mHeaderTextView.setText(mHeaderText);
|
||||
} else {
|
||||
mHeaderTextView.setText(R.string.lockpattern_need_to_unlock);
|
||||
}
|
||||
if (mFooterText != null) {
|
||||
mFooterTextView.setText(mFooterText);
|
||||
} else {
|
||||
mFooterTextView.setText(R.string.lockpattern_need_to_unlock_footer);
|
||||
}
|
||||
|
||||
mLockPatternView.setEnabled(true);
|
||||
mLockPatternView.enableInput();
|
||||
break;
|
||||
case NeedToUnlockWrong:
|
||||
if (mHeaderWrongText != null) {
|
||||
mHeaderTextView.setText(mHeaderWrongText);
|
||||
} else {
|
||||
mHeaderTextView.setText(R.string.lockpattern_need_to_unlock_wrong);
|
||||
}
|
||||
if (mFooterWrongText != null) {
|
||||
mFooterTextView.setText(mFooterWrongText);
|
||||
} else {
|
||||
mFooterTextView.setText(R.string.lockpattern_need_to_unlock_wrong_footer);
|
||||
}
|
||||
|
||||
mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong);
|
||||
mLockPatternView.setEnabled(true);
|
||||
mLockPatternView.enableInput();
|
||||
break;
|
||||
case LockedOut:
|
||||
mLockPatternView.clearPattern();
|
||||
// enabled = false means: disable input, and have the
|
||||
// appearance of being disabled.
|
||||
mLockPatternView.setEnabled(false); // appearance of being disabled
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private Runnable mClearPatternRunnable = new Runnable() {
|
||||
public void run() {
|
||||
mLockPatternView.clearPattern();
|
||||
}
|
||||
};
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* The pattern listener that responds according to a user confirming
|
||||
* an existing lock pattern.
|
||||
*/
|
||||
private LockPatternView.OnPatternListener mConfirmExistingLockPatternListener = new LockPatternView.OnPatternListener() {
|
||||
|
||||
public void onPatternStart() {
|
||||
mLockPatternView.removeCallbacks(mClearPatternRunnable);
|
||||
}
|
||||
|
||||
public void onPatternCleared() {
|
||||
mLockPatternView.removeCallbacks(mClearPatternRunnable);
|
||||
}
|
||||
|
||||
public void onPatternCellAdded(List<Cell> pattern) {
|
||||
|
||||
}
|
||||
|
||||
public void onPatternDetected(List<LockPatternView.Cell> pattern) {
|
||||
if (mLockPatternUtils.checkPattern(pattern)) {
|
||||
setResult(RESULT_OK);
|
||||
finish();
|
||||
if (savedInstanceState != null) {
|
||||
mNumWrongConfirmAttempts = savedInstanceState.getInt(KEY_NUM_WRONG_ATTEMPTS);
|
||||
} else {
|
||||
if (pattern.size() >= LockPatternUtils.MIN_PATTERN_REGISTER_FAIL &&
|
||||
++mNumWrongConfirmAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) {
|
||||
long deadline = mLockPatternUtils.setLockoutAttemptDeadline();
|
||||
handleAttemptLockout(deadline);
|
||||
} else {
|
||||
updateStage(Stage.NeedToUnlockWrong);
|
||||
postClearPatternRunnable();
|
||||
// on first launch, if no lock pattern is set, then finish with
|
||||
// success (don't want user to get stuck confirming something that
|
||||
// doesn't exist).
|
||||
if (!mLockPatternUtils.savedPatternExists()) {
|
||||
getActivity().setResult(Activity.RESULT_OK);
|
||||
getActivity().finish();
|
||||
}
|
||||
}
|
||||
return view;
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
// deliberately not calling super since we are managing this in full
|
||||
outState.putInt(KEY_NUM_WRONG_ATTEMPTS, mNumWrongConfirmAttempts);
|
||||
}
|
||||
|
||||
private void handleAttemptLockout(long elapsedRealtimeDeadline) {
|
||||
updateStage(Stage.LockedOut);
|
||||
long elapsedRealtime = SystemClock.elapsedRealtime();
|
||||
mCountdownTimer = new CountDownTimer(
|
||||
elapsedRealtimeDeadline - elapsedRealtime,
|
||||
LockPatternUtils.FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS) {
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
|
||||
@Override
|
||||
public void onTick(long millisUntilFinished) {
|
||||
mHeaderTextView.setText(R.string.lockpattern_too_many_failed_confirmation_attempts_header);
|
||||
final int secondsCountdown = (int) (millisUntilFinished / 1000);
|
||||
mFooterTextView.setText(getString(
|
||||
R.string.lockpattern_too_many_failed_confirmation_attempts_footer,
|
||||
secondsCountdown));
|
||||
if (mCountdownTimer != null) {
|
||||
mCountdownTimer.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
// if the user is currently locked out, enforce it.
|
||||
long deadline = mLockPatternUtils.getLockoutAttemptDeadline();
|
||||
if (deadline != 0) {
|
||||
handleAttemptLockout(deadline);
|
||||
} else if (!mLockPatternView.isEnabled()) {
|
||||
// The deadline has passed, but the timer was cancelled...
|
||||
// Need to clean up.
|
||||
mNumWrongConfirmAttempts = 0;
|
||||
updateStage(Stage.NeedToUnlock);
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
|
||||
private void updateStage(Stage stage) {
|
||||
|
||||
switch (stage) {
|
||||
case NeedToUnlock:
|
||||
if (mHeaderText != null) {
|
||||
mHeaderTextView.setText(mHeaderText);
|
||||
} else {
|
||||
mHeaderTextView.setText(R.string.lockpattern_need_to_unlock);
|
||||
}
|
||||
if (mFooterText != null) {
|
||||
mFooterTextView.setText(mFooterText);
|
||||
} else {
|
||||
mFooterTextView.setText(R.string.lockpattern_need_to_unlock_footer);
|
||||
}
|
||||
|
||||
mLockPatternView.setEnabled(true);
|
||||
mLockPatternView.enableInput();
|
||||
break;
|
||||
case NeedToUnlockWrong:
|
||||
if (mHeaderWrongText != null) {
|
||||
mHeaderTextView.setText(mHeaderWrongText);
|
||||
} else {
|
||||
mHeaderTextView.setText(R.string.lockpattern_need_to_unlock_wrong);
|
||||
}
|
||||
if (mFooterWrongText != null) {
|
||||
mFooterTextView.setText(mFooterWrongText);
|
||||
} else {
|
||||
mFooterTextView.setText(R.string.lockpattern_need_to_unlock_wrong_footer);
|
||||
}
|
||||
|
||||
mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong);
|
||||
mLockPatternView.setEnabled(true);
|
||||
mLockPatternView.enableInput();
|
||||
break;
|
||||
case LockedOut:
|
||||
mLockPatternView.clearPattern();
|
||||
// enabled = false means: disable input, and have the
|
||||
// appearance of being disabled.
|
||||
mLockPatternView.setEnabled(false); // appearance of being disabled
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private Runnable mClearPatternRunnable = new Runnable() {
|
||||
public void run() {
|
||||
mLockPatternView.clearPattern();
|
||||
}
|
||||
};
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* The pattern listener that responds according to a user confirming
|
||||
* an existing lock pattern.
|
||||
*/
|
||||
private LockPatternView.OnPatternListener mConfirmExistingLockPatternListener
|
||||
= new LockPatternView.OnPatternListener() {
|
||||
|
||||
public void onPatternStart() {
|
||||
mLockPatternView.removeCallbacks(mClearPatternRunnable);
|
||||
}
|
||||
|
||||
public void onPatternCleared() {
|
||||
mLockPatternView.removeCallbacks(mClearPatternRunnable);
|
||||
}
|
||||
|
||||
public void onPatternCellAdded(List<Cell> pattern) {
|
||||
|
||||
}
|
||||
|
||||
public void onPatternDetected(List<LockPatternView.Cell> pattern) {
|
||||
if (mLockPatternUtils.checkPattern(pattern)) {
|
||||
getActivity().setResult(Activity.RESULT_OK);
|
||||
getActivity().finish();
|
||||
} else {
|
||||
if (pattern.size() >= LockPatternUtils.MIN_PATTERN_REGISTER_FAIL &&
|
||||
++mNumWrongConfirmAttempts
|
||||
>= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) {
|
||||
long deadline = mLockPatternUtils.setLockoutAttemptDeadline();
|
||||
handleAttemptLockout(deadline);
|
||||
} else {
|
||||
updateStage(Stage.NeedToUnlockWrong);
|
||||
postClearPatternRunnable();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private void handleAttemptLockout(long elapsedRealtimeDeadline) {
|
||||
updateStage(Stage.LockedOut);
|
||||
long elapsedRealtime = SystemClock.elapsedRealtime();
|
||||
mCountdownTimer = new CountDownTimer(
|
||||
elapsedRealtimeDeadline - elapsedRealtime,
|
||||
LockPatternUtils.FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS) {
|
||||
|
||||
@Override
|
||||
public void onTick(long millisUntilFinished) {
|
||||
mHeaderTextView.setText(R.string.lockpattern_too_many_failed_confirmation_attempts_header);
|
||||
final int secondsCountdown = (int) (millisUntilFinished / 1000);
|
||||
mFooterTextView.setText(getString(
|
||||
R.string.lockpattern_too_many_failed_confirmation_attempts_footer,
|
||||
secondsCountdown));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
mNumWrongConfirmAttempts = 0;
|
||||
updateStage(Stage.NeedToUnlock);
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -90,6 +90,8 @@ public class SecuritySettings extends SettingsPreferenceFragment
|
||||
private static final int SET_OR_CHANGE_LOCK_METHOD_REQUEST = 123;
|
||||
private static final int FALLBACK_LOCK_AFTER_TIMEOUT_VALUE = 5000; // compatible with pre-Froyo
|
||||
|
||||
private static final String TAG = "SecuritySettings";
|
||||
|
||||
// Credential storage
|
||||
private final CredentialStorage mCredentialStorage = new CredentialStorage();
|
||||
|
||||
@@ -359,8 +361,8 @@ public class SecuritySettings extends SettingsPreferenceFragment
|
||||
|
||||
final LockPatternUtils lockPatternUtils = mChooseLockSettingsHelper.utils();
|
||||
if (KEY_UNLOCK_SET_OR_CHANGE.equals(key)) {
|
||||
Intent intent = new Intent(getActivity(), ChooseLockGeneric.class);
|
||||
startActivityForResult(intent, SET_OR_CHANGE_LOCK_METHOD_REQUEST);
|
||||
startFragment(this, "com.android.settings.ChooseLockGeneric$ChooseLockGenericFragment",
|
||||
SET_OR_CHANGE_LOCK_METHOD_REQUEST, null);
|
||||
} else if (KEY_LOCK_ENABLED.equals(key)) {
|
||||
lockPatternUtils.setLockPatternEnabled(isToggled(preference));
|
||||
} else if (KEY_VISIBLE_PATTERN.equals(key)) {
|
||||
|
Reference in New Issue
Block a user