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" />
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/topLayout"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
@@ -45,18 +44,12 @@
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
/>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"/>
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:orientation="horizontal">
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
|
||||
<Button
|
||||
style="@android:style/Widget.Material.Button.Borderless"
|
||||
@@ -69,11 +62,17 @@
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="14dp"/>
|
||||
|
||||
<EditText android:id="@+id/password_entry"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.android.settings.widget.ScrollToParentEditText
|
||||
android:id="@+id/password_entry"
|
||||
android:layout_width="208dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal|bottom"
|
||||
android:layout_marginBottom="26dp"
|
||||
android:inputType="textPassword"
|
||||
android:imeOptions="actionNext|flagNoFullscreen|flagForceAscii"
|
||||
android:gravity="center"
|
||||
@@ -85,9 +84,10 @@
|
||||
android:id="@+id/errorText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal|bottom"
|
||||
android:layout_marginBottom="10dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/fingerprintIcon"
|
||||
android:layout_gravity="end|bottom"
|
||||
|
@@ -42,8 +42,17 @@
|
||||
android:lines="2"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<!-- Password entry field -->
|
||||
<EditText android:id="@+id/password_entry"
|
||||
<com.android.settings.widget.ScrollToParentEditText
|
||||
android:id="@+id/password_entry"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
@@ -53,14 +62,6 @@
|
||||
android:textSize="24sp"
|
||||
style="@style/TextAppearance.PasswordEntry"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/bottom_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="vertical">
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/password_requirements_view"
|
||||
android:layout_width="match_parent"
|
||||
|
@@ -47,8 +47,7 @@
|
||||
android:layout_marginEnd="?attr/confirmDeviceCredentialsSideMargin"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
/>
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<Button
|
||||
style="@android:style/Widget.Material.Button.Borderless"
|
||||
@@ -64,12 +63,16 @@
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
<EditText
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.android.settings.widget.ScrollToParentEditText
|
||||
android:id="@+id/password_entry"
|
||||
android:layout_width="208dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="-40dp"
|
||||
android:inputType="textPassword"
|
||||
android:imeOptions="actionNext|flagNoFullscreen|flagForceAscii"
|
||||
android:gravity="center"
|
||||
@@ -81,12 +84,15 @@
|
||||
android:accessibilityLiveRegion="polite"
|
||||
android:id="@+id/errorText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:gravity="center_vertical"/>
|
||||
android:layout_marginEnd="12dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<View android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/fingerprintIcon"
|
||||
|
@@ -19,7 +19,6 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:icon="@drawable/ic_lock"
|
||||
android:layout="@layout/suw_glif_blank_template"
|
||||
android:importantForAutofill="noExcludeDescendants">
|
||||
|
||||
<com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
|
||||
@@ -28,19 +27,6 @@
|
||||
android:layout_width="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
|
||||
android:id="@+id/detailsText"
|
||||
style="@style/SuwDescription.Glif"
|
||||
@@ -54,12 +40,17 @@
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<EditText
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.android.settings.widget.ScrollToParentEditText
|
||||
android:id="@+id/password_entry"
|
||||
android:layout_width="208dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="-40dp"
|
||||
android:inputType="textPassword"
|
||||
android:imeOptions="actionNext|flagNoFullscreen|flagForceAscii"
|
||||
android:gravity="center"
|
||||
@@ -67,16 +58,18 @@
|
||||
style="@style/TextAppearance.PasswordEntry"/>
|
||||
|
||||
<TextView
|
||||
style="@style/TextAppearance.ConfirmDeviceCredentialsErrorText"
|
||||
android:accessibilityLiveRegion="polite"
|
||||
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_weight="1"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:gravity="center_vertical"/>
|
||||
android:layout_weight="1" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/fingerprintIcon"
|
||||
|
@@ -300,9 +300,6 @@
|
||||
<dimen name="support_spacer_height">8dp</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 -->
|
||||
<dimen name="support_escalation_card_padding_start">40dp</dimen>
|
||||
|
@@ -16,12 +16,19 @@
|
||||
|
||||
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.Fragment;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.app.admin.PasswordMetrics;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.InsetDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
@@ -34,13 +41,15 @@ import android.text.Selection;
|
||||
import android.text.Spannable;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewParent;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
@@ -59,12 +68,6 @@ import com.android.setupwizardlib.GlifLayout;
|
||||
import java.util.ArrayList;
|
||||
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 static final String PASSWORD_MIN_KEY = "lockscreen.password_min";
|
||||
public static final String PASSWORD_MAX_KEY = "lockscreen.password_max";
|
||||
@@ -357,23 +360,6 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
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) {
|
||||
final SettingsActivity sa = (SettingsActivity) activity;
|
||||
int id = mIsAlphaMode ? R.string.lockpassword_choose_your_password_header
|
||||
|
@@ -136,6 +136,9 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
|
||||
mPasswordEntryInputDisabler = new TextViewInputDisabler(mPasswordEntry);
|
||||
|
||||
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);
|
||||
mErrorTextView = (TextView) view.findViewById(R.id.errorText);
|
||||
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