Refactor choose lock password scrolling
Replace the negative margin + inset background hack with a overriding call to requestRectangleOnScreen, which will also make a best effort to show all the password requirements if there are multiple of them. Bug: 38236574 Test: Added ScrollToParentEditTextTest Change-Id: Id570652b64434b2d0b25c231540375d93884aaa9
This commit is contained in:
@@ -22,7 +22,6 @@
|
|||||||
<include layout="@layout/confirm_lock_background_base" />
|
<include layout="@layout/confirm_lock_background_base" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:id="@+id/topLayout"
|
android:id="@+id/topLayout"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -45,18 +44,12 @@
|
|||||||
android:layout_marginEnd="24dp"
|
android:layout_marginEnd="24dp"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"/>
|
||||||
/>
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:layout_weight="1"/>
|
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:orientation="horizontal">
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1">
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
style="@android:style/Widget.Material.Button.Borderless"
|
style="@android:style/Widget.Material.Button.Borderless"
|
||||||
@@ -69,24 +62,31 @@
|
|||||||
android:layout_marginEnd="8dp"
|
android:layout_marginEnd="8dp"
|
||||||
android:layout_marginBottom="14dp"/>
|
android:layout_marginBottom="14dp"/>
|
||||||
|
|
||||||
<EditText android:id="@+id/password_entry"
|
<LinearLayout
|
||||||
android:layout_width="208dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_horizontal|bottom"
|
android:layout_gravity="center_vertical"
|
||||||
android:layout_marginBottom="26dp"
|
android:gravity="center_horizontal"
|
||||||
android:inputType="textPassword"
|
android:orientation="vertical">
|
||||||
android:imeOptions="actionNext|flagNoFullscreen|flagForceAscii"
|
|
||||||
android:gravity="center"
|
|
||||||
android:textSize="16sp"
|
|
||||||
style="@style/TextAppearance.PasswordEntry"/>
|
|
||||||
|
|
||||||
<TextView style="@style/TextAppearance.ConfirmDeviceCredentialsErrorText"
|
<com.android.settings.widget.ScrollToParentEditText
|
||||||
android:accessibilityLiveRegion="polite"
|
android:id="@+id/password_entry"
|
||||||
android:id="@+id/errorText"
|
android:layout_width="208dp"
|
||||||
android:layout_width="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:inputType="textPassword"
|
||||||
android:layout_gravity="center_horizontal|bottom"
|
android:imeOptions="actionNext|flagNoFullscreen|flagForceAscii"
|
||||||
android:layout_marginBottom="10dp"/>
|
android:gravity="center"
|
||||||
|
android:textSize="16sp"
|
||||||
|
style="@style/TextAppearance.PasswordEntry"/>
|
||||||
|
|
||||||
|
<TextView style="@style/TextAppearance.ConfirmDeviceCredentialsErrorText"
|
||||||
|
android:accessibilityLiveRegion="polite"
|
||||||
|
android:id="@+id/errorText"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="10dp"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/fingerprintIcon"
|
android:id="@+id/fingerprintIcon"
|
||||||
|
@@ -42,29 +42,30 @@
|
|||||||
android:lines="2"
|
android:lines="2"
|
||||||
android:textAppearance="?android:attr/textAppearanceMedium"/>
|
android:textAppearance="?android:attr/textAppearanceMedium"/>
|
||||||
|
|
||||||
<!-- Password entry field -->
|
<LinearLayout
|
||||||
<EditText android:id="@+id/password_entry"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:clipChildren="false"
|
||||||
android:gravity="center"
|
android:clipToPadding="false"
|
||||||
android:inputType="textPassword"
|
android:orientation="vertical"
|
||||||
android:imeOptions="actionNext|flagNoExtractUi|flagForceAscii"
|
android:paddingBottom="8dp">
|
||||||
android:textSize="24sp"
|
|
||||||
style="@style/TextAppearance.PasswordEntry"/>
|
|
||||||
|
|
||||||
<LinearLayout
|
<!-- Password entry field -->
|
||||||
android:id="@+id/bottom_container"
|
<com.android.settings.widget.ScrollToParentEditText
|
||||||
|
android:id="@+id/password_entry"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:clipChildren="false"
|
android:layout_gravity="center"
|
||||||
android:clipToPadding="false"
|
android:gravity="center"
|
||||||
android:orientation="vertical">
|
android:inputType="textPassword"
|
||||||
|
android:imeOptions="actionNext|flagNoExtractUi|flagForceAscii"
|
||||||
|
android:textSize="24sp"
|
||||||
|
style="@style/TextAppearance.PasswordEntry"/>
|
||||||
|
|
||||||
<android.support.v7.widget.RecyclerView
|
<android.support.v7.widget.RecyclerView
|
||||||
android:id="@+id/password_requirements_view"
|
android:id="@+id/password_requirements_view"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"/>
|
android:layout_height="wrap_content"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
@@ -47,8 +47,7 @@
|
|||||||
android:layout_marginEnd="?attr/confirmDeviceCredentialsSideMargin"
|
android:layout_marginEnd="?attr/confirmDeviceCredentialsSideMargin"
|
||||||
android:layout_marginTop="12dp"
|
android:layout_marginTop="12dp"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content" />
|
||||||
/>
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
style="@android:style/Widget.Material.Button.Borderless"
|
style="@android:style/Widget.Material.Button.Borderless"
|
||||||
@@ -64,29 +63,36 @@
|
|||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_weight="1"/>
|
android:layout_weight="1"/>
|
||||||
|
|
||||||
<EditText
|
<LinearLayout
|
||||||
android:id="@+id/password_entry"
|
android:layout_width="match_parent"
|
||||||
android:layout_width="208dp"
|
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_horizontal"
|
android:gravity="center_horizontal"
|
||||||
android:layout_marginTop="-40dp"
|
android:orientation="vertical">
|
||||||
android:inputType="textPassword"
|
|
||||||
android:imeOptions="actionNext|flagNoFullscreen|flagForceAscii"
|
|
||||||
android:gravity="center"
|
|
||||||
android:textSize="16sp"
|
|
||||||
style="@style/TextAppearance.PasswordEntry"/>
|
|
||||||
|
|
||||||
<TextView
|
<com.android.settings.widget.ScrollToParentEditText
|
||||||
style="@style/TextAppearance.ConfirmDeviceCredentialsErrorText"
|
android:id="@+id/password_entry"
|
||||||
android:accessibilityLiveRegion="polite"
|
android:layout_width="208dp"
|
||||||
android:id="@+id/errorText"
|
android:layout_height="wrap_content"
|
||||||
android:layout_width="wrap_content"
|
android:inputType="textPassword"
|
||||||
|
android:imeOptions="actionNext|flagNoFullscreen|flagForceAscii"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textSize="16sp"
|
||||||
|
style="@style/TextAppearance.PasswordEntry"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/TextAppearance.ConfirmDeviceCredentialsErrorText"
|
||||||
|
android:accessibilityLiveRegion="polite"
|
||||||
|
android:id="@+id/errorText"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:layout_marginEnd="12dp"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"/>
|
||||||
android:layout_gravity="center_horizontal"
|
|
||||||
android:layout_marginStart="12dp"
|
|
||||||
android:layout_marginEnd="12dp"
|
|
||||||
android:gravity="center_vertical"/>
|
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/fingerprintIcon"
|
android:id="@+id/fingerprintIcon"
|
||||||
|
@@ -19,7 +19,6 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:icon="@drawable/ic_lock"
|
android:icon="@drawable/ic_lock"
|
||||||
android:layout="@layout/suw_glif_blank_template"
|
|
||||||
android:importantForAutofill="noExcludeDescendants">
|
android:importantForAutofill="noExcludeDescendants">
|
||||||
|
|
||||||
<com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
|
<com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
|
||||||
@@ -28,19 +27,6 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/suw_layout_icon"
|
|
||||||
style="@style/SuwGlifIcon"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:src="@drawable/ic_lock" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/headerText"
|
|
||||||
style="@style/SuwGlifHeaderTitle"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/detailsText"
|
android:id="@+id/detailsText"
|
||||||
style="@style/SuwDescription.Glif"
|
style="@style/SuwDescription.Glif"
|
||||||
@@ -54,29 +40,36 @@
|
|||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_weight="1" />
|
android:layout_weight="1" />
|
||||||
|
|
||||||
<EditText
|
<LinearLayout
|
||||||
android:id="@+id/password_entry"
|
android:layout_width="match_parent"
|
||||||
android:layout_width="208dp"
|
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_horizontal"
|
android:gravity="center_horizontal"
|
||||||
android:layout_marginTop="-40dp"
|
android:orientation="vertical">
|
||||||
android:inputType="textPassword"
|
|
||||||
android:imeOptions="actionNext|flagNoFullscreen|flagForceAscii"
|
|
||||||
android:gravity="center"
|
|
||||||
android:textSize="16sp"
|
|
||||||
style="@style/TextAppearance.PasswordEntry"/>
|
|
||||||
|
|
||||||
<TextView
|
<com.android.settings.widget.ScrollToParentEditText
|
||||||
style="@style/TextAppearance.ConfirmDeviceCredentialsErrorText"
|
android:id="@+id/password_entry"
|
||||||
android:accessibilityLiveRegion="polite"
|
android:layout_width="208dp"
|
||||||
android:id="@+id/errorText"
|
android:layout_height="wrap_content"
|
||||||
android:layout_width="wrap_content"
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:inputType="textPassword"
|
||||||
|
android:imeOptions="actionNext|flagNoFullscreen|flagForceAscii"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textSize="16sp"
|
||||||
|
style="@style/TextAppearance.PasswordEntry"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/errorText"
|
||||||
|
style="@style/TextAppearance.ConfirmDeviceCredentialsErrorText"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:accessibilityLiveRegion="polite"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<Space
|
||||||
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1" />
|
||||||
android:layout_gravity="center_horizontal"
|
|
||||||
android:layout_marginStart="12dp"
|
|
||||||
android:layout_marginEnd="12dp"
|
|
||||||
android:gravity="center_vertical"/>
|
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/fingerprintIcon"
|
android:id="@+id/fingerprintIcon"
|
||||||
|
@@ -300,9 +300,6 @@
|
|||||||
<dimen name="support_spacer_height">8dp</dimen>
|
<dimen name="support_spacer_height">8dp</dimen>
|
||||||
|
|
||||||
<dimen name="password_requirement_textsize">14sp</dimen>
|
<dimen name="password_requirement_textsize">14sp</dimen>
|
||||||
<!-- Visible vertical space we want to show below password edittext field when ime is shown.
|
|
||||||
The unit is sp as it is related to the text size of password requirement item. -->
|
|
||||||
<dimen name="visible_vertical_space_below_password">20sp</dimen>
|
|
||||||
|
|
||||||
<!-- Padding for the escalation card in normal dimens -->
|
<!-- Padding for the escalation card in normal dimens -->
|
||||||
<dimen name="support_escalation_card_padding_start">40dp</dimen>
|
<dimen name="support_escalation_card_padding_start">40dp</dimen>
|
||||||
|
@@ -16,12 +16,19 @@
|
|||||||
|
|
||||||
package com.android.settings;
|
package com.android.settings;
|
||||||
|
|
||||||
|
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
|
||||||
|
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
|
||||||
|
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
|
||||||
|
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
|
||||||
|
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
import android.app.admin.DevicePolicyManager;
|
import android.app.admin.DevicePolicyManager;
|
||||||
import android.app.admin.PasswordMetrics;
|
import android.app.admin.PasswordMetrics;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.graphics.Rect;
|
||||||
import android.graphics.drawable.InsetDrawable;
|
import android.graphics.drawable.InsetDrawable;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
@@ -34,13 +41,15 @@ import android.text.Selection;
|
|||||||
import android.text.Spannable;
|
import android.text.Spannable;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
|
import android.util.AttributeSet;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.inputmethod.EditorInfo;
|
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.view.ViewParent;
|
||||||
|
import android.view.inputmethod.EditorInfo;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
@@ -59,12 +68,6 @@ import com.android.setupwizardlib.GlifLayout;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
|
|
||||||
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
|
|
||||||
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
|
|
||||||
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
|
|
||||||
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
|
|
||||||
|
|
||||||
public class ChooseLockPassword extends SettingsActivity {
|
public class ChooseLockPassword extends SettingsActivity {
|
||||||
public static final String PASSWORD_MIN_KEY = "lockscreen.password_min";
|
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_MAX_KEY = "lockscreen.password_max";
|
||||||
@@ -357,23 +360,6 @@ public class ChooseLockPassword extends SettingsActivity {
|
|||||||
FRAGMENT_TAG_SAVE_AND_FINISH);
|
FRAGMENT_TAG_SAVE_AND_FINISH);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Workaround to show one password requirement below EditText when IME is shown.
|
|
||||||
// By adding an inset to the edit text background, we make the EditText occupy more
|
|
||||||
// vertical space, and the keyboard will then avoid hiding it. We have also set
|
|
||||||
// negative margin in the layout below in order to have them show in the correct
|
|
||||||
// position.
|
|
||||||
final int visibleVerticalSpaceBelowPassword =
|
|
||||||
getResources().getDimensionPixelOffset(
|
|
||||||
R.dimen.visible_vertical_space_below_password);
|
|
||||||
InsetDrawable drawable =
|
|
||||||
new InsetDrawable(
|
|
||||||
mPasswordEntry.getBackground(), 0, 0, 0, visibleVerticalSpaceBelowPassword);
|
|
||||||
mPasswordEntry.setBackgroundDrawable(drawable);
|
|
||||||
LinearLayout bottomContainer = (LinearLayout) view.findViewById(R.id.bottom_container);
|
|
||||||
LinearLayout.LayoutParams bottomContainerLp =
|
|
||||||
(LinearLayout.LayoutParams) bottomContainer.getLayoutParams();
|
|
||||||
bottomContainerLp.setMargins(0, -visibleVerticalSpaceBelowPassword, 0, 0);
|
|
||||||
|
|
||||||
if (activity instanceof SettingsActivity) {
|
if (activity instanceof SettingsActivity) {
|
||||||
final SettingsActivity sa = (SettingsActivity) activity;
|
final SettingsActivity sa = (SettingsActivity) activity;
|
||||||
int id = mIsAlphaMode ? R.string.lockpassword_choose_your_password_header
|
int id = mIsAlphaMode ? R.string.lockpassword_choose_your_password_header
|
||||||
|
@@ -136,6 +136,9 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
|
|||||||
mPasswordEntryInputDisabler = new TextViewInputDisabler(mPasswordEntry);
|
mPasswordEntryInputDisabler = new TextViewInputDisabler(mPasswordEntry);
|
||||||
|
|
||||||
mHeaderTextView = (TextView) view.findViewById(R.id.headerText);
|
mHeaderTextView = (TextView) view.findViewById(R.id.headerText);
|
||||||
|
if (mHeaderTextView == null) {
|
||||||
|
mHeaderTextView = view.findViewById(R.id.suw_layout_title);
|
||||||
|
}
|
||||||
mDetailsTextView = (TextView) view.findViewById(R.id.detailsText);
|
mDetailsTextView = (TextView) view.findViewById(R.id.detailsText);
|
||||||
mErrorTextView = (TextView) view.findViewById(R.id.errorText);
|
mErrorTextView = (TextView) view.findViewById(R.id.errorText);
|
||||||
mIsAlpha = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == storedQuality
|
mIsAlpha = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == storedQuality
|
||||||
|
51
src/com/android/settings/widget/ScrollToParentEditText.java
Normal file
51
src/com/android/settings/widget/ScrollToParentEditText.java
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.widget;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewParent;
|
||||||
|
import android.widget.EditText;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An EditText that, instead of scrolling to itself when focused, will request scrolling to its
|
||||||
|
* parent. This is used in ChooseLockPassword to do make a best effort for not hiding the error
|
||||||
|
* messages for why the password is invalid under the keyboard.
|
||||||
|
*/
|
||||||
|
public class ScrollToParentEditText extends EditText {
|
||||||
|
|
||||||
|
private Rect mRect = new Rect();
|
||||||
|
|
||||||
|
public ScrollToParentEditText(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean requestRectangleOnScreen(Rect rectangle, boolean immediate) {
|
||||||
|
ViewParent parent = getParent();
|
||||||
|
if (parent instanceof View) {
|
||||||
|
// Request the entire parent view to be shown, which in ChooseLockPassword's case,
|
||||||
|
// will include messages for why the password is invalid (if any).
|
||||||
|
((View) parent).getDrawingRect(mRect);
|
||||||
|
return ((View) parent).requestRectangleOnScreen(mRect, immediate);
|
||||||
|
} else {
|
||||||
|
return super.requestRectangleOnScreen(rectangle, immediate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.widget;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.mockito.Matchers.any;
|
||||||
|
import static org.mockito.Matchers.anyBoolean;
|
||||||
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.robolectric.RuntimeEnvironment.application;
|
||||||
|
import static org.robolectric.Shadows.shadowOf;
|
||||||
|
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
|
||||||
|
import com.android.settings.SettingsRobolectricTestRunner;
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.robolectric.Robolectric;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
import org.robolectric.shadows.ShadowView;
|
||||||
|
|
||||||
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||||
|
public class ScrollToParentEditTextTest {
|
||||||
|
|
||||||
|
private static final int EDIT_TEXT_SIZE = 20;
|
||||||
|
private static final int PARENT_SIZE = 50;
|
||||||
|
private static final int SCROLL_RECT_SIZE = 30;
|
||||||
|
|
||||||
|
private ScrollToParentEditText mEditText;
|
||||||
|
private FrameLayout mParent;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
mEditText = new ScrollToParentEditText(
|
||||||
|
application,
|
||||||
|
Robolectric.buildAttributeSet().build());
|
||||||
|
mEditText.layout(0, 0, EDIT_TEXT_SIZE, EDIT_TEXT_SIZE);
|
||||||
|
|
||||||
|
mParent = spy(new FrameLayout(application));
|
||||||
|
mParent.layout(0, 0, PARENT_SIZE, PARENT_SIZE);
|
||||||
|
|
||||||
|
doReturn(true).when(mParent).requestRectangleOnScreen(any(Rect.class), anyBoolean());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void requestRectangleOnScreen_noParent_shouldScrollToItself() {
|
||||||
|
assertThat(mEditText.requestRectangleOnScreen(
|
||||||
|
new Rect(0, 0, SCROLL_RECT_SIZE, SCROLL_RECT_SIZE), true)).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void requestRectangleOnScreen_withParent_shouldScrollToParent() {
|
||||||
|
ShadowView shadowEditText = shadowOf(mEditText);
|
||||||
|
shadowEditText.setMyParent(mParent);
|
||||||
|
|
||||||
|
assertThat(mEditText.requestRectangleOnScreen(
|
||||||
|
new Rect(0, 0, SCROLL_RECT_SIZE, SCROLL_RECT_SIZE), true)).isTrue();
|
||||||
|
verify(mParent)
|
||||||
|
.requestRectangleOnScreen(eq(new Rect(0, 0, PARENT_SIZE, PARENT_SIZE)), eq(true));
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user