diff options
author | Xin Li <delphij@google.com> | 2021-08-14 06:31:21 +0000 |
---|---|---|
committer | Xin Li <delphij@google.com> | 2021-08-14 06:31:21 +0000 |
commit | 0cc7edea8e2bd634fb708f6076b1f93fb1eb145b (patch) | |
tree | 033a2ea54f61c1238a5e634fdcc6ee9b4c81fc3a | |
parent | 7185f7160457e933c51e895305064bf56afaf5c1 (diff) | |
parent | 31ea2a449d4f0e2d2674e3a9d28c5a3b25753d3f (diff) | |
download | setupwizard-temp_sam_202323961.tar.gz |
Merge sc-dev-plus-aosp-without-vendor@7634622temp_sam_202323961
Merged-In: Idf5e47d6f18d89bcdef7433e15d1c8f0529b0351
Change-Id: I08740b2e36340d196b0a64d1ab75ae2d3541b603
16 files changed, 394 insertions, 65 deletions
diff --git a/library/main/res/drawable/car_ic_close.xml b/library/main/res/drawable/car_ic_close.xml new file mode 100644 index 0000000..08b5e36 --- /dev/null +++ b/library/main/res/drawable/car_ic_close.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (C) 2020 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="@dimen/car_primary_icon_size" + android:height="@dimen/car_primary_icon_size" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12 19,6.41z" + android:fillColor="@color/car_tint_light"/> +</vector> diff --git a/library/main/res/layout/car_setup_wizard_toolbar.xml b/library/main/res/layout/car_setup_wizard_toolbar.xml index 5c5703b..5ae4e11 100644 --- a/library/main/res/layout/car_setup_wizard_toolbar.xml +++ b/library/main/res/layout/car_setup_wizard_toolbar.xml @@ -37,6 +37,15 @@ android:background="@drawable/button_ripple_bg" android:contentDescription="@string/back_button_content_description" android:src="@drawable/car_ic_arrow_back"/> + + <ImageView + android:id="@+id/close_button" + android:layout_width="@dimen/car_primary_icon_size" + android:layout_height="@dimen/car_primary_icon_size" + android:layout_gravity="center" + android:background="@drawable/button_ripple_bg" + android:contentDescription="@string/close_button_content_description" + android:src="@drawable/car_ic_close"/> </FrameLayout> <TextView diff --git a/library/main/res/values/attrs.xml b/library/main/res/values/attrs.xml index 74bb14e..31d2f5b 100644 --- a/library/main/res/values/attrs.xml +++ b/library/main/res/values/attrs.xml @@ -68,6 +68,8 @@ <declare-styleable name="CarSetupWizardBaseLayout"> <!-- Attributes related to the visibility of the back button --> <attr name="showBackButton"/> + <!-- Attributes related to the visibility of the close button --> + <attr name="showCloseButton" format="boolean"/> <!-- Attributes related to the visibility and text of the toolbar title --> <attr name="showToolbarTitle"/> diff --git a/library/main/res/values/strings.xml b/library/main/res/values/strings.xml index beb37dc..027a683 100644 --- a/library/main/res/values/strings.xml +++ b/library/main/res/values/strings.xml @@ -17,4 +17,7 @@ <resources> <!-- Content description of the back button for accessibility services like Tallback [CHAR LIMIT=120] --> <string name="back_button_content_description">Navigate back</string> + + <!-- Content description of the close button for accessibility services like Tallback [CHAR LIMIT=120] --> + <string name="close_button_content_description">Close</string> </resources>
\ No newline at end of file diff --git a/library/main/src/com/android/car/setupwizardlib/BaseSetupWizardActivity.java b/library/main/src/com/android/car/setupwizardlib/BaseSetupWizardActivity.java index a2fdff3..36caae0 100644 --- a/library/main/src/com/android/car/setupwizardlib/BaseSetupWizardActivity.java +++ b/library/main/src/com/android/car/setupwizardlib/BaseSetupWizardActivity.java @@ -97,6 +97,8 @@ abstract class BaseSetupWizardActivity extends FragmentActivity { } }); + mCarSetupWizardLayout.setCloseButtonListener(v-> handleCloseButton()); + resetPrimaryToolbarButtonOnClickListener(); resetSecondaryToolbarButtonOnClickListener(); @@ -255,6 +257,14 @@ abstract class BaseSetupWizardActivity extends FragmentActivity { } /** + * Method to be overwritten by subclasses wanting to implement their own close behavior. + * Default behavior is finishAction. + */ + protected void handleCloseButton() { + finishAction(); + } + + /** * Called when nextAction has been invoked, should be overridden on derived class when it is * needed perform work when nextAction has been invoked. */ @@ -350,6 +360,14 @@ abstract class BaseSetupWizardActivity extends FragmentActivity { } /** + * Sets whether the close button is visible. If this value is {@code true}, clicking the button + * will finish the current flow. + */ + protected void setCloseButtonVisible(boolean visible) { + mCarSetupWizardLayout.setCloseButtonVisible(visible); + } + + /** * Sets whether the toolbar title is visible. */ protected void setToolbarTitleVisible(boolean visible) { diff --git a/library/main/src/com/android/car/setupwizardlib/CarSetupWizardBaseLayout.java b/library/main/src/com/android/car/setupwizardlib/CarSetupWizardBaseLayout.java index 43d300e..715315a 100644 --- a/library/main/src/com/android/car/setupwizardlib/CarSetupWizardBaseLayout.java +++ b/library/main/src/com/android/car/setupwizardlib/CarSetupWizardBaseLayout.java @@ -63,6 +63,7 @@ class CarSetupWizardBaseLayout extends LinearLayout { private static final float IMAGE_MIRROR_ROTATION = 180.0f; private View mBackButton; + private View mCloseButton; private View mTitleBar; private TextView mToolbarTitle; private PartnerConfigHelper mPartnerConfigHelper; @@ -120,6 +121,7 @@ class CarSetupWizardBaseLayout extends LinearLayout { */ private void init(TypedArray attrArray) { boolean showBackButton; + boolean showCloseButton; boolean showToolbarTitle; String toolbarTitleText; @@ -138,6 +140,8 @@ class CarSetupWizardBaseLayout extends LinearLayout { try { showBackButton = attrArray.getBoolean( R.styleable.CarSetupWizardBaseLayout_showBackButton, true); + showCloseButton = attrArray.getBoolean( + R.styleable.CarSetupWizardBaseLayout_showCloseButton, false); showToolbarTitle = attrArray.getBoolean( R.styleable.CarSetupWizardBaseLayout_showToolbarTitle, false); toolbarTitleText = attrArray.getString( @@ -171,18 +175,34 @@ class CarSetupWizardBaseLayout extends LinearLayout { toolbar.setLayoutDirection(View.LAYOUT_DIRECTION_LTR); setBackButton(findViewById(R.id.back_button)); + setCloseButton(findViewById(R.id.close_button)); + Drawable drawable = mPartnerConfigHelper.getDrawable( getContext(), PartnerConfig.CONFIG_TOOLBAR_BUTTON_ICON_BACK); if (drawable != null) { ((ImageView) mBackButton).setImageDrawable(drawable); } + Drawable closeButtonDrawable = mPartnerConfigHelper.getDrawable( + getContext(), PartnerConfig.CONFIG_TOOLBAR_BUTTON_ICON_CLOSE); + if (closeButtonDrawable != null) { + ((ImageView) mCloseButton).setImageDrawable(closeButtonDrawable); + } + if (shouldMirrorNavIcons()) { Log.v(TAG, "Mirroring navigation icons"); mBackButton.setRotation(IMAGE_MIRROR_ROTATION); + mCloseButton.setRotation(IMAGE_MIRROR_ROTATION); } + if (showBackButton && showCloseButton) { + Log.w(TAG, "Showing Back and Close button simultaneously is not supported"); + } + + // Set the back button visibility based on the custom attribute. setBackButtonVisible(showBackButton); + // Set the close button visibility based on the custom attribute. + setCloseButtonVisible(showCloseButton); // Se the title bar. setTitleBar(findViewById(R.id.application_bar)); @@ -252,19 +272,25 @@ class CarSetupWizardBaseLayout extends LinearLayout { */ @VisibleForTesting void setViewVisible(View view, boolean visible) { + if (view == null) { + return; + } view.setVisibility(visible ? View.VISIBLE : View.GONE); } // Add or remove the back button touch delegate depending on whether it is visible. @VisibleForTesting - void updateBackButtonTouchDelegate(boolean visible) { + void updateNavigationButtonTouchDelegate(View button, boolean visible) { + if (button == null) { + return; + } if (visible) { // Post this action in the parent's message queue to make sure the parent // lays out its children before getHitRect() is called this.post(() -> { Rect delegateArea = new Rect(); - mBackButton.getHitRect(delegateArea); + button.getHitRect(delegateArea); /* * Update the delegate area based on the difference between the current size and @@ -283,17 +309,16 @@ class CarSetupWizardBaseLayout extends LinearLayout { delegateArea.top -= sizeDifference; // Set the TouchDelegate on the parent view - TouchDelegate touchDelegate = new TouchDelegate(delegateArea, - mBackButton); + TouchDelegate touchDelegate = new TouchDelegate(delegateArea, button); - if (View.class.isInstance(mBackButton.getParent())) { - ((View) mBackButton.getParent()).setTouchDelegate(touchDelegate); + if (View.class.isInstance(button.getParent())) { + ((View) button.getParent()).setTouchDelegate(touchDelegate); } }); } else { // Set the TouchDelegate to null if the back button is not visible. - if (View.class.isInstance(mBackButton.getParent())) { - ((View) mBackButton.getParent()).setTouchDelegate(null); + if (View.class.isInstance(button.getParent())) { + ((View) button.getParent()).setTouchDelegate(null); } } } @@ -322,8 +347,41 @@ class CarSetupWizardBaseLayout extends LinearLayout { * Set the back button visibility to the given visibility. */ public void setBackButtonVisible(boolean visible) { + if (visible) { + setViewVisible(mCloseButton, false); + updateNavigationButtonTouchDelegate(mCloseButton, false); + } setViewVisible(mBackButton, visible); - updateBackButtonTouchDelegate(visible); + updateNavigationButtonTouchDelegate(mBackButton, visible); + } + + public View getCloseButton() { + return mCloseButton; + } + + @VisibleForTesting + final void setCloseButton(View closeButton) { + mCloseButton = closeButton; + } + + /** + * Set the close button onClickListener to given listener. Can be null if the listener should + * be overridden so no callback is made. + */ + public void setCloseButtonListener(@Nullable View.OnClickListener listener) { + mCloseButton.setOnClickListener(listener); + } + + /** + * Set the back button visibility to the given visibility. + */ + public void setCloseButtonVisible(boolean visible) { + if (visible) { + setViewVisible(mBackButton, false); + updateNavigationButtonTouchDelegate(mBackButton, false); + } + setViewVisible(mCloseButton, visible); + updateNavigationButtonTouchDelegate(mCloseButton, visible); } /** diff --git a/library/main/src/com/android/car/setupwizardlib/partner/PartnerConfig.java b/library/main/src/com/android/car/setupwizardlib/partner/PartnerConfig.java index 27ea753..54d1e6e 100644 --- a/library/main/src/com/android/car/setupwizardlib/partner/PartnerConfig.java +++ b/library/main/src/com/android/car/setupwizardlib/partner/PartnerConfig.java @@ -28,6 +28,9 @@ public enum PartnerConfig { CONFIG_TOOLBAR_BUTTON_ICON_BACK( PartnerConfigKey.KEY_TOOLBAR_BUTTON_ICON_BACK, ResourceType.DRAWABLE), + CONFIG_TOOLBAR_BUTTON_ICON_CLOSE( + PartnerConfigKey.KEY_TOOLBAR_BUTTON_ICON_CLOSE, ResourceType.DRAWABLE), + CONFIG_TOOLBAR_NAV_ICON_MIRRORING_IN_RTL( PartnerConfigKey.KEY_TOOLBAR_NAV_BUTTON_MIRRORING_IN_RTL, ResourceType.BOOLEAN), diff --git a/library/main/src/com/android/car/setupwizardlib/partner/PartnerConfigKey.java b/library/main/src/com/android/car/setupwizardlib/partner/PartnerConfigKey.java index 8556fa7..7f9dadd 100644 --- a/library/main/src/com/android/car/setupwizardlib/partner/PartnerConfigKey.java +++ b/library/main/src/com/android/car/setupwizardlib/partner/PartnerConfigKey.java @@ -26,6 +26,7 @@ import java.lang.annotation.RetentionPolicy; PartnerConfigKey.KEY_IMMERSIVE_MODE, PartnerConfigKey.KEY_TOOLBAR_BG_COLOR, PartnerConfigKey.KEY_TOOLBAR_BUTTON_ICON_BACK, + PartnerConfigKey.KEY_TOOLBAR_BUTTON_ICON_CLOSE, PartnerConfigKey.KEY_TOOLBAR_NAV_BUTTON_MIRRORING_IN_RTL, PartnerConfigKey.KEY_TOOLBAR_BUTTON_FONT_FAMILY, PartnerConfigKey.KEY_TOOLBAR_BUTTON_PADDING_HORIZONTAL, @@ -55,6 +56,8 @@ public @interface PartnerConfigKey { String KEY_TOOLBAR_BUTTON_ICON_BACK = "suw_compat_toolbar_button_icon_back"; + String KEY_TOOLBAR_BUTTON_ICON_CLOSE = "suw_compat_toolbar_button_icon_close"; + String KEY_TOOLBAR_NAV_BUTTON_MIRRORING_IN_RTL = "suw_compat_toolbar_nav_button_mirroring_in_rtl"; diff --git a/library/main/src/com/android/car/setupwizardlib/summary/PartnerSummaryActionsCollector.java b/library/main/src/com/android/car/setupwizardlib/summary/PartnerSummaryActionsCollector.java index ebf0d35..2dfb04b 100644 --- a/library/main/src/com/android/car/setupwizardlib/summary/PartnerSummaryActionsCollector.java +++ b/library/main/src/com/android/car/setupwizardlib/summary/PartnerSummaryActionsCollector.java @@ -86,14 +86,14 @@ public class PartnerSummaryActionsCollector { ResolveInfo resolveInfo = getSummaryContentProviderResolveInfo(context.getPackageManager()); if (resolveInfo == null) { - Log.e(TAG, "Could not find partner content provider, ignoring partner summary items."); + Log.i(TAG, "Could not find partner content provider, ignoring partner summary items."); return; } mContentProviderUri = getSummaryContentProviderUri(resolveInfo); if (mContentProviderUri == null) { - Log.e(TAG, "Could not fetch content provider URI, ignoring partner summary items."); + Log.i(TAG, "Could not fetch content provider URI, ignoring partner summary items."); } } diff --git a/library/main/src/com/android/car/setupwizardlib/util/CarWizardManagerHelper.java b/library/main/src/com/android/car/setupwizardlib/util/CarWizardManagerHelper.java index 7f5cf7a..ff83b55 100644 --- a/library/main/src/com/android/car/setupwizardlib/util/CarWizardManagerHelper.java +++ b/library/main/src/com/android/car/setupwizardlib/util/CarWizardManagerHelper.java @@ -148,4 +148,25 @@ public final class CarWizardManagerHelper { return Settings.Global.getInt(context.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) == 1; } + /** + * Checks whether an intent is running in the initial setup wizard flow. + * + * @param intent The intent to be checked, usually from {@link Activity#getIntent()}. + * @return true if the intent passed in was intended to be used with setup wizard. + */ + public static boolean isInitialSetupWizard(Intent intent) { + return intent.getBooleanExtra(EXTRA_IS_FIRST_RUN, false); + } + + /** + * Checks whether an intent is running in the deferred setup wizard flow. + * + * @param originalIntent The original intent that was used to start the step, usually via {@link + * Activity#getIntent()}. + * @return true if the intent passed in was running in deferred setup wizard. + */ + public static boolean isDeferredSetupWizard(Intent originalIntent) { + return originalIntent != null && originalIntent.getBooleanExtra(EXTRA_IS_DEFERRED_SETUP, + false); + } } diff --git a/library/main/src/com/android/car/setupwizardlib/util/ResultCodes.java b/library/main/src/com/android/car/setupwizardlib/util/ResultCodes.java index 604e8b0..89b8d11 100644 --- a/library/main/src/com/android/car/setupwizardlib/util/ResultCodes.java +++ b/library/main/src/com/android/car/setupwizardlib/util/ResultCodes.java @@ -23,7 +23,11 @@ import static android.app.Activity.RESULT_FIRST_USER; */ public final class ResultCodes { public static final int RESULT_SKIP = RESULT_FIRST_USER; + public static final int RESULT_RETRY = RESULT_FIRST_USER + 1; public static final int RESULT_ACTIVITY_NOT_FOUND = RESULT_FIRST_USER + 2; + public static final int RESULT_LIFECYCLE_NOT_MATCHED = RESULT_FIRST_USER + 3; + public static final int RESULT_FLOW_NOT_MATCHED = RESULT_FIRST_USER + 4; + public static final int RESULT_FIRST_SETUP_USER = RESULT_FIRST_USER + 100; private ResultCodes() { diff --git a/library/main/tests/robotests/res/values/attrs.xml b/library/main/tests/robotests/res/values/attrs.xml index 4454939..0591552 100644 --- a/library/main/tests/robotests/res/values/attrs.xml +++ b/library/main/tests/robotests/res/values/attrs.xml @@ -19,6 +19,8 @@ <declare-styleable name="CarSetupWizardBaseLayout"> <!-- Attributes related to the visibility of the back button --> <attr name="showBackButton" format="boolean"/> + <!-- Attributes related to the visibility of the close button --> + <attr name="showCloseButton" format="boolean"/> <!-- Attributes related to the visibility and text of the toolbar title --> <attr name="showToolbarTitle" format="boolean"/> diff --git a/library/main/tests/robotests/src/com/android/car/setupwizardlib/CarSetupWizardCompatLayoutTest.java b/library/main/tests/robotests/src/com/android/car/setupwizardlib/CarSetupWizardCompatLayoutTest.java index 541cf4c..3ed02c0 100644 --- a/library/main/tests/robotests/src/com/android/car/setupwizardlib/CarSetupWizardCompatLayoutTest.java +++ b/library/main/tests/robotests/src/com/android/car/setupwizardlib/CarSetupWizardCompatLayoutTest.java @@ -104,8 +104,22 @@ public class CarSetupWizardCompatLayoutTest extends BaseRobolectricTest { } /** + * Test that {@link CarSetupWizardCompatLayout#setCloseButtonListener} does set the close button + * listener. + */ + @Test + public void testSetCloseButtonListener() { + View.OnClickListener spyListener = TestHelper.createSpyListener(); + + mCarSetupWizardCompatLayout.setCloseButtonListener(spyListener); + mCarSetupWizardCompatLayout.getCloseButton().performClick(); + Mockito.verify(spyListener).onClick(mCarSetupWizardCompatLayout.getCloseButton()); + } + + /** * Test that {@link CarSetupWizardCompatLayout#setBackButtonVisible} does set the view - * visible/not visible and calls updateBackButtonTouchDelegate. + * visible/not visible and calls + * {@link CarSetupWizardDesignLayout#updateNavigationButtonTouchDelegate(View, boolean)}. */ @Test public void testSetBackButtonVisibleTrue() { @@ -115,12 +129,18 @@ public class CarSetupWizardCompatLayoutTest extends BaseRobolectricTest { spyCarSetupWizardCompatLayout.setBackButtonVisible(true); View backButton = spyCarSetupWizardCompatLayout.getBackButton(); TestHelper.assertViewVisible(backButton); - Mockito.verify(spyCarSetupWizardCompatLayout).updateBackButtonTouchDelegate(true); + Mockito.verify(spyCarSetupWizardCompatLayout) + .updateNavigationButtonTouchDelegate(backButton, true); + View closeButton = spyCarSetupWizardCompatLayout.getCloseButton(); + TestHelper.assertViewNotVisible(closeButton); + Mockito.verify(spyCarSetupWizardCompatLayout) + .updateNavigationButtonTouchDelegate(closeButton, false); } /** * Test that {@link CarSetupWizardCompatLayout#setBackButtonVisible} does set the view - * visible/not visible and calls updateBackButtonTouchDelegate. + * visible/not visible and calls + * {@link CarSetupWizardDesignLayout#updateNavigationButtonTouchDelegate(View, boolean)}. */ @Test public void testSetBackButtonVisibleFalse() { @@ -130,7 +150,47 @@ public class CarSetupWizardCompatLayoutTest extends BaseRobolectricTest { spyCarSetupWizardCompatLayout.setBackButtonVisible(false); View backButton = spyCarSetupWizardCompatLayout.getBackButton(); TestHelper.assertViewNotVisible(backButton); - Mockito.verify(spyCarSetupWizardCompatLayout).updateBackButtonTouchDelegate(false); + Mockito.verify(spyCarSetupWizardCompatLayout) + .updateNavigationButtonTouchDelegate(backButton, false); + } + + /** + * Test that {@link CarSetupWizardCompatLayout#setCloseButtonVisible} does set the view + * visible/not visible and calls + * {@link CarSetupWizardDesignLayout#updateNavigationButtonTouchDelegate(View, boolean)}. + */ + @Test + public void testSetCloseButtonVisibleTrue() { + CarSetupWizardCompatLayout spyCarSetupWizardCompatLayout = + Mockito.spy(mCarSetupWizardCompatLayout); + + spyCarSetupWizardCompatLayout.setCloseButtonVisible(true); + View closeButton = spyCarSetupWizardCompatLayout.getCloseButton(); + TestHelper.assertViewVisible(closeButton); + Mockito.verify(spyCarSetupWizardCompatLayout) + .updateNavigationButtonTouchDelegate(closeButton, true); + View backButton = spyCarSetupWizardCompatLayout.getBackButton(); + TestHelper.assertViewNotVisible(backButton); + Mockito.verify(spyCarSetupWizardCompatLayout) + .updateNavigationButtonTouchDelegate(backButton, false); + } + + + /** + * Test that {@link CarSetupWizardCompatLayout#setCloseButtonVisible} does set the view + * visible/not visible and calls + * {@link CarSetupWizardDesignLayout#updateNavigationButtonTouchDelegate(View, boolean)}. + */ + @Test + public void testSetCloseButtonVisibleFalse() { + CarSetupWizardCompatLayout spyCarSetupWizardCompatLayout = + Mockito.spy(mCarSetupWizardCompatLayout); + + spyCarSetupWizardCompatLayout.setCloseButtonVisible(false); + View closeButton = spyCarSetupWizardCompatLayout.getCloseButton(); + TestHelper.assertViewNotVisible(closeButton); + Mockito.verify(spyCarSetupWizardCompatLayout) + .updateNavigationButtonTouchDelegate(closeButton, false); } /** diff --git a/library/utils/src/com/android/car/setupwizardlib/InitialLockSetupClient.java b/library/utils/src/com/android/car/setupwizardlib/InitialLockSetupClient.java index 4ef851e..6c7830f 100644 --- a/library/utils/src/com/android/car/setupwizardlib/InitialLockSetupClient.java +++ b/library/utils/src/com/android/car/setupwizardlib/InitialLockSetupClient.java @@ -16,11 +16,13 @@ package com.android.car.setupwizardlib; +import android.app.KeyguardManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.AsyncTask; +import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -28,6 +30,7 @@ import android.os.RemoteException; import android.util.Log; import com.android.car.setupwizardlib.InitialLockSetupConstants.LockTypes; +import com.android.car.setupwizardlib.InitialLockSetupConstants.PasswordComplexity; import com.android.car.setupwizardlib.InitialLockSetupConstants.SetLockCodes; import com.android.car.setupwizardlib.InitialLockSetupConstants.ValidateLockFlags; @@ -56,6 +59,7 @@ public class InitialLockSetupClient implements ServiceConnection { private InitialLockListener mInitialLockListener; private Context mContext; + private KeyguardManager mKeyguardManager; private IInitialLockSetupService mInitialLockSetupService; private ValidateLockAsyncTask mCurrentValidateLockTask; private SaveLockAsyncTask mCurrentSaveLockTask; @@ -65,6 +69,7 @@ public class InitialLockSetupClient implements ServiceConnection { public InitialLockSetupClient(Context context) { mContext = context.getApplicationContext(); + mKeyguardManager = mContext.getSystemService(KeyguardManager.class); } /** @@ -120,8 +125,8 @@ public class InitialLockSetupClient implements ServiceConnection { * Fetches the set of {@link LockConfig}s that define the lock constraints for the device. */ public void getLockConfigs() { - LockConfigsAsyncTask lockConfigsAsyncTask = new LockConfigsAsyncTask(mInitialLockListener, - mInitialLockSetupService); + LockConfigsAsyncTask lockConfigsAsyncTask = new LockConfigsAsyncTask( + mInitialLockListener, mInitialLockSetupService, mKeyguardManager); lockConfigsAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, null); } @@ -136,8 +141,8 @@ public class InitialLockSetupClient implements ServiceConnection { && mCurrentValidateLockTask.getStatus() != AsyncTask.Status.FINISHED) { mCurrentValidateLockTask.cancel(true); } - mCurrentValidateLockTask = new ValidateLockAsyncTask( - mInitialLockListener, mInitialLockSetupService, LockTypes.PASSWORD); + mCurrentValidateLockTask = new ValidateLockAsyncTask(mInitialLockListener, + mInitialLockSetupService, mKeyguardManager, LockTypes.PASSWORD); mCurrentValidateLockTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, password); } @@ -151,8 +156,8 @@ public class InitialLockSetupClient implements ServiceConnection { && mCurrentValidateLockTask.getStatus() != AsyncTask.Status.FINISHED) { mCurrentValidateLockTask.cancel(true); } - mCurrentValidateLockTask = new ValidateLockAsyncTask( - mInitialLockListener, mInitialLockSetupService, LockTypes.PIN); + mCurrentValidateLockTask = new ValidateLockAsyncTask(mInitialLockListener, + mInitialLockSetupService, mKeyguardManager, LockTypes.PIN); mCurrentValidateLockTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, pin); } @@ -166,8 +171,8 @@ public class InitialLockSetupClient implements ServiceConnection { && mCurrentValidateLockTask.getStatus() != AsyncTask.Status.FINISHED) { mCurrentValidateLockTask.cancel(true); } - mCurrentValidateLockTask = new ValidateLockAsyncTask( - mInitialLockListener, mInitialLockSetupService, LockTypes.PATTERN); + mCurrentValidateLockTask = new ValidateLockAsyncTask(mInitialLockListener, + mInitialLockSetupService, mKeyguardManager, LockTypes.PATTERN); mCurrentValidateLockTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, pattern); } @@ -184,7 +189,7 @@ public class InitialLockSetupClient implements ServiceConnection { return; } mCurrentSaveLockTask = new SaveLockAsyncTask(mInitialLockListener, - mInitialLockSetupService, LockTypes.PASSWORD); + mInitialLockSetupService, mKeyguardManager, LockTypes.PASSWORD); mCurrentSaveLockTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, password); } @@ -200,7 +205,7 @@ public class InitialLockSetupClient implements ServiceConnection { return; } mCurrentSaveLockTask = new SaveLockAsyncTask(mInitialLockListener, - mInitialLockSetupService, LockTypes.PIN); + mInitialLockSetupService, mKeyguardManager, LockTypes.PIN); mCurrentSaveLockTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, pin); } @@ -217,7 +222,7 @@ public class InitialLockSetupClient implements ServiceConnection { return; } mCurrentSaveLockTask = new SaveLockAsyncTask(mInitialLockListener, - mInitialLockSetupService, LockTypes.PATTERN); + mInitialLockSetupService, mKeyguardManager, LockTypes.PATTERN); mCurrentSaveLockTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, pattern); } @@ -282,29 +287,56 @@ public class InitialLockSetupClient implements ServiceConnection { private WeakReference<InitialLockListener> mInitialLockListener; private WeakReference<IInitialLockSetupService> mInitialLockSetupService; + private WeakReference<KeyguardManager> mKeyguardManager; LockConfigsAsyncTask(InitialLockListener initialLockListener, - IInitialLockSetupService initialLockSetupService) { + IInitialLockSetupService initialLockSetupService, + KeyguardManager keyguardManager) { mInitialLockListener = new WeakReference<>(initialLockListener); mInitialLockSetupService = new WeakReference<>(initialLockSetupService); + mKeyguardManager = new WeakReference<>(keyguardManager); } @Override protected Map<Integer, LockConfig> doInBackground(Void... voids) { - IInitialLockSetupService initialLockSetupService = mInitialLockSetupService.get(); - if (initialLockSetupService == null) { - InitialLockSetupClient.logVerbose( - "Lost reference to service in LockConfigsAsyncTask"); - return null; - } LockConfig passwordConfig, pinConfig, patternConfig; - try { - passwordConfig = initialLockSetupService.getLockConfig(LockTypes.PASSWORD); - pinConfig = initialLockSetupService.getLockConfig(LockTypes.PIN); - patternConfig = initialLockSetupService.getLockConfig(LockTypes.PATTERN); - } catch (RemoteException e) { - e.printStackTrace(); - return null; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + KeyguardManager km = mKeyguardManager.get(); + if (km == null) { + InitialLockSetupClient.logVerbose( + "Lost reference to keyguardManager in LockConfigsAsyncTask"); + return null; + } + passwordConfig = + new LockConfig( + /* enabled= */ true, + km.getMinLockLength( + /* isPin= */ false, PasswordComplexity.PASSWORD_COMPLEXITY_MEDIUM)); + pinConfig = + new LockConfig( + /* enabled= */ true, + km.getMinLockLength( + /* isPin= */ true, PasswordComplexity.PASSWORD_COMPLEXITY_LOW)); + patternConfig = + new LockConfig( + /* enabled= */ true, + km.getMinLockLength( + /* isPin= */ false, PasswordComplexity.PASSWORD_COMPLEXITY_LOW)); + } else { + IInitialLockSetupService initialLockSetupService = mInitialLockSetupService.get(); + if (initialLockSetupService == null) { + InitialLockSetupClient.logVerbose( + "Lost reference to service in LockConfigsAsyncTask"); + return null; + } + try { + passwordConfig = initialLockSetupService.getLockConfig(LockTypes.PASSWORD); + pinConfig = initialLockSetupService.getLockConfig(LockTypes.PIN); + patternConfig = initialLockSetupService.getLockConfig(LockTypes.PATTERN); + } catch (RemoteException e) { + e.printStackTrace(); + return null; + } } Map<Integer, LockConfig> map = new HashMap<>(); map.put(LockTypes.PASSWORD, passwordConfig); @@ -327,32 +359,64 @@ public class InitialLockSetupClient implements ServiceConnection { private WeakReference<InitialLockListener> mInitialLockListener; private WeakReference<IInitialLockSetupService> mInitialLockSetupService; + private WeakReference<KeyguardManager> mKeyguardManager; private int mLockType; ValidateLockAsyncTask( InitialLockListener initialLockListener, IInitialLockSetupService initialLockSetupService, + KeyguardManager keyguardManager, @LockTypes int lockType) { mInitialLockListener = new WeakReference<>(initialLockListener); mInitialLockSetupService = new WeakReference<>(initialLockSetupService); + mKeyguardManager = new WeakReference<>(keyguardManager); mLockType = lockType; } @Override protected Integer doInBackground(byte[]... passwords) { InitialLockSetupClient.logVerbose("ValidateLockAsyncTask doInBackground"); - IInitialLockSetupService initialLockSetupService = mInitialLockSetupService.get(); - if (initialLockSetupService == null) { - InitialLockSetupClient.logVerbose( - "Lost reference to service in ValidateLockAsyncTask"); - return ValidateLockFlags.INVALID_GENERIC; - } - try { - int output = initialLockSetupService.checkValidLock(mLockType, passwords[0]); - return output; - } catch (RemoteException e) { - e.printStackTrace(); - return ValidateLockFlags.INVALID_GENERIC; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + KeyguardManager km = mKeyguardManager.get(); + if (km == null) { + InitialLockSetupClient.logVerbose( + "Lost reference to keyguardManager in LockConfigsAsyncTask"); + return null; + } + int complexity; + switch (mLockType) { + case LockTypes.PASSWORD: + complexity = PasswordComplexity.PASSWORD_COMPLEXITY_MEDIUM; + break; + case LockTypes.PIN: + complexity = PasswordComplexity.PASSWORD_COMPLEXITY_LOW; + break; + case LockTypes.PATTERN: + complexity = PasswordComplexity.PASSWORD_COMPLEXITY_LOW; + passwords[0] = + InitialLockSetupHelper.getNumericEquivalentByteArray(passwords[0]); + break; + default: + Log.e(TAG, "other lock type, returning generic error"); + return ValidateLockFlags.INVALID_GENERIC; + } + return km.isValidLockPasswordComplexity(mLockType, passwords[0], complexity) + ? 0 + : ValidateLockFlags.INVALID_GENERIC; + } else { + IInitialLockSetupService initialLockSetupService = mInitialLockSetupService.get(); + if (initialLockSetupService == null) { + InitialLockSetupClient.logVerbose( + "Lost reference to service in ValidateLockAsyncTask"); + return ValidateLockFlags.INVALID_GENERIC; + } + try { + int output = initialLockSetupService.checkValidLock(mLockType, passwords[0]); + return output; + } catch (RemoteException e) { + e.printStackTrace(); + return ValidateLockFlags.INVALID_GENERIC; + } } } @@ -373,32 +437,64 @@ public class InitialLockSetupClient implements ServiceConnection { private WeakReference<InitialLockListener> mInitialLockListener; private WeakReference<IInitialLockSetupService> mInitialLockSetupService; + private WeakReference<KeyguardManager> mKeyguardManager; private int mLockType; SaveLockAsyncTask( InitialLockListener initialLockListener, IInitialLockSetupService initialLockSetupService, + KeyguardManager keyguardManager, @LockTypes int lockType) { mInitialLockListener = new WeakReference<>(initialLockListener); mInitialLockSetupService = new WeakReference<>(initialLockSetupService); + mKeyguardManager = new WeakReference<>(keyguardManager); mLockType = lockType; } @Override protected Integer doInBackground(byte[]... passwords) { InitialLockSetupClient.logVerbose("SaveLockAsyncTask doInBackground"); - IInitialLockSetupService initialLockSetupService = mInitialLockSetupService.get(); - if (initialLockSetupService == null) { - InitialLockSetupClient.logVerbose( - "Lost reference to service in SaveLockAsyncTask"); - return SetLockCodes.FAIL_LOCK_GENERIC; - } - try { - int output = initialLockSetupService.setLock(mLockType, passwords[0]); - return output; - } catch (RemoteException e) { - e.printStackTrace(); - return SetLockCodes.FAIL_LOCK_GENERIC; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + KeyguardManager km = mKeyguardManager.get(); + if (km == null) { + InitialLockSetupClient.logVerbose( + "Lost reference to keyguardManager in SaveLockAsyncTask"); + return null; + } + int complexity; + switch (mLockType) { + case LockTypes.PASSWORD: + complexity = PasswordComplexity.PASSWORD_COMPLEXITY_MEDIUM; + break; + case LockTypes.PIN: + complexity = PasswordComplexity.PASSWORD_COMPLEXITY_LOW; + break; + case LockTypes.PATTERN: + complexity = PasswordComplexity.PASSWORD_COMPLEXITY_LOW; + passwords[0] = + InitialLockSetupHelper.getNumericEquivalentByteArray(passwords[0]); + break; + default: + Log.e(TAG, "other lock type, returning generic error"); + return SetLockCodes.FAIL_LOCK_GENERIC; + } + return km.setLock(mLockType, passwords[0], complexity) + ? 1 + : SetLockCodes.FAIL_LOCK_GENERIC; + } else { + IInitialLockSetupService initialLockSetupService = mInitialLockSetupService.get(); + if (initialLockSetupService == null) { + InitialLockSetupClient.logVerbose( + "Lost reference to service in SaveLockAsyncTask"); + return SetLockCodes.FAIL_LOCK_GENERIC; + } + try { + int output = initialLockSetupService.setLock(mLockType, passwords[0]); + return output; + } catch (RemoteException e) { + e.printStackTrace(); + return SetLockCodes.FAIL_LOCK_GENERIC; + } } } diff --git a/library/utils/src/com/android/car/setupwizardlib/InitialLockSetupConstants.java b/library/utils/src/com/android/car/setupwizardlib/InitialLockSetupConstants.java index 7081e78..8ca5c6e 100644 --- a/library/utils/src/com/android/car/setupwizardlib/InitialLockSetupConstants.java +++ b/library/utils/src/com/android/car/setupwizardlib/InitialLockSetupConstants.java @@ -36,12 +36,14 @@ public interface InitialLockSetupConstants { @IntDef({ LockTypes.PASSWORD, LockTypes.PIN, - LockTypes.PATTERN + LockTypes.PATTERN, + LockTypes.NONE }) @interface LockTypes { int PASSWORD = 0; int PIN = 1; int PATTERN = 2; + int NONE = 3; } /** @@ -75,5 +77,19 @@ public interface InitialLockSetupConstants { int FAIL_LOCK_INVALID = -2; int FAIL_LOCK_GENERIC = -3; } + + /** PasswordComplexity as defined in DevicePolicyManager. */ + @IntDef({ + PasswordComplexity.PASSWORD_COMPLEXITY_NONE, + PasswordComplexity.PASSWORD_COMPLEXITY_LOW, + PasswordComplexity.PASSWORD_COMPLEXITY_MEDIUM, + PasswordComplexity.PASSWORD_COMPLEXITY_HIGH, + }) + @interface PasswordComplexity { + int PASSWORD_COMPLEXITY_NONE = 0; + int PASSWORD_COMPLEXITY_LOW = 0x10000; + int PASSWORD_COMPLEXITY_MEDIUM = 0x30000; + int PASSWORD_COMPLEXITY_HIGH = 0x50000; + } } diff --git a/library/utils/src/com/android/car/setupwizardlib/InitialLockSetupHelper.java b/library/utils/src/com/android/car/setupwizardlib/InitialLockSetupHelper.java index 9820680..191ddbc 100644 --- a/library/utils/src/com/android/car/setupwizardlib/InitialLockSetupHelper.java +++ b/library/utils/src/com/android/car/setupwizardlib/InitialLockSetupHelper.java @@ -81,4 +81,13 @@ public class InitialLockSetupHelper { } return charSequence; } + + /** Return an ASCII-equivalent array of character digits for a numeric byte input. */ + public static byte[] getNumericEquivalentByteArray(byte[] input) { + byte[] output = new byte[input.length]; + for (int i = 0; i < input.length; i++) { + output[i] = (byte) (input[i] + 48); + } + return output; + } } |