From af87233e1e713dd5b91789210a8a78ffc880c24a Mon Sep 17 00:00:00 2001 From: josephpv Date: Wed, 24 Jul 2024 14:20:11 +0000 Subject: [PATCH] Show different error screen for PS creation based on error This contains the change to show a different fragment on private space creation error based on the error code returned by UserManager. On private space create error checks for the returned error code and if PS is not supported on the device showns error screen containing a link to Help Center atricle to find out more about the reason for profile creation failure. ACTION_PRIVATE_SPACE_SETUP_SPACE_ERRORS metric is logged with the error code on create error else 0 on sucessful space creation. Recording: b/340130375#comment17 Bug: 340130375 Test: Manual Flag: android.multiuser.show_different_creation_error_for_unsupported_devices Change-Id: Ifa0345fb6aad64599009f8aa79d168f57fd35c03 --- .../privatespace_main_context_nav.xml | 6 ++ res/values/strings.xml | 6 ++ ...PrivateProfileCreationRestrictedError.java | 99 +++++++++++++++++++ .../PrivateSpaceCreationFragment.java | 31 +++++- .../privatespace/PrivateSpaceMaintainer.java | 9 ++ 5 files changed, 149 insertions(+), 2 deletions(-) create mode 100644 src/com/android/settings/privatespace/PrivateProfileCreationRestrictedError.java diff --git a/res/navigation/privatespace_main_context_nav.xml b/res/navigation/privatespace_main_context_nav.xml index 3eb57d3ecda..e20eaff5206 100644 --- a/res/navigation/privatespace_main_context_nav.xml +++ b/res/navigation/privatespace_main_context_nav.xml @@ -35,6 +35,9 @@ + + Couldn\u2019t set up a private space Try Again + + Exit + + Private space isn\u2019t available.\nView possible causes + + View possible causes Choose a new lock for private space? diff --git a/src/com/android/settings/privatespace/PrivateProfileCreationRestrictedError.java b/src/com/android/settings/privatespace/PrivateProfileCreationRestrictedError.java new file mode 100644 index 00000000000..d2bdb8cbe79 --- /dev/null +++ b/src/com/android/settings/privatespace/PrivateProfileCreationRestrictedError.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2024 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.privatespace; + +import android.app.Activity; +import android.app.settings.SettingsEnums; +import android.os.Bundle; +import android.text.util.Linkify; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.activity.OnBackPressedCallback; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.settings.R; +import com.android.settings.core.InstrumentedFragment; + +import com.google.android.setupcompat.template.FooterBarMixin; +import com.google.android.setupcompat.template.FooterButton; +import com.google.android.setupdesign.GlifLayout; + +import java.util.regex.Pattern; + +public class PrivateProfileCreationRestrictedError extends InstrumentedFragment { + private static final String TAG = "PrivateSpaceCreationErr"; + + @NonNull + @Override + public View onCreateView( + @NonNull LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + GlifLayout rootView = + (GlifLayout) + inflater.inflate(R.layout.privatespace_creation_error, container, false); + final FooterBarMixin mixin = rootView.getMixin(FooterBarMixin.class); + mixin.setPrimaryButton( + new FooterButton.Builder(getContext()) + .setText(R.string.private_space_exit_label) + .setListener(onExit()) + .setButtonType(FooterButton.ButtonType.NEXT) + .setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Primary) + .build()); + OnBackPressedCallback callback = + new OnBackPressedCallback(true /* enabled by default */) { + @Override + public void handleOnBackPressed() { + // Handle the back button event. We intentionally don't want to allow back + // button to work in this screen during the setup flow. + } + }; + requireActivity().getOnBackPressedDispatcher().addCallback(this, callback); + rootView.setDescriptionText(R.string.private_space_error_description); + TextView textView = rootView.getDescriptionTextView(); + Pattern pattern = Pattern.compile(getString(R.string.private_space_error_causes_text)); + Linkify.addLinks( + textView, + pattern, + getString(R.string.private_space_learn_more_url)); + + return rootView; + } + + @Override + public int getMetricsCategory() { + return SettingsEnums.PRIVATE_SPACE_SETUP_SPACE_CREATION_ERROR; + } + + private View.OnClickListener onExit() { + return v -> { + Activity activity = getActivity(); + if (activity != null) { + mMetricsFeatureProvider.action( + getContext(), SettingsEnums.ACTION_PRIVATE_SPACE_SETUP_CANCEL_CREATE_SPACE); + Log.i(TAG, "private space setup exited"); + activity.finish(); + } + }; + } +} + diff --git a/src/com/android/settings/privatespace/PrivateSpaceCreationFragment.java b/src/com/android/settings/privatespace/PrivateSpaceCreationFragment.java index ce85d7238cc..0bfedbd394e 100644 --- a/src/com/android/settings/privatespace/PrivateSpaceCreationFragment.java +++ b/src/com/android/settings/privatespace/PrivateSpaceCreationFragment.java @@ -29,6 +29,7 @@ import android.net.NetworkInfo; import android.os.Bundle; import android.os.Handler; import android.os.Looper; +import android.os.UserManager; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -49,6 +50,7 @@ public class PrivateSpaceCreationFragment extends InstrumentedFragment { private static final String TAG = "PrivateSpaceCreateFrag"; private static final int PRIVATE_SPACE_CREATE_POST_DELAY_MS = 1000; private static final int PRIVATE_SPACE_ACCOUNT_LOGIN_POST_DELAY_MS = 5000; + private static final int PRIVATE_SPACE_SETUP_NO_ERROR = 0; private static final Handler sHandler = new Handler(Looper.getMainLooper()); private Runnable mRunnable = () -> { @@ -122,6 +124,11 @@ public class PrivateSpaceCreationFragment extends InstrumentedFragment { Log.i(TAG, "Private Space created"); mMetricsFeatureProvider.action( getContext(), SettingsEnums.ACTION_PRIVATE_SPACE_SETUP_SPACE_CREATED, true); + if (android.multiuser.Flags.showDifferentCreationErrorForUnsupportedDevices()) { + mMetricsFeatureProvider.action( + getContext(), SettingsEnums.ACTION_PRIVATE_SPACE_SETUP_SPACE_ERRORS, + PRIVATE_SPACE_SETUP_NO_ERROR); + } if (isConnectedToInternet()) { registerReceiver(); sHandler.postDelayed( @@ -132,8 +139,18 @@ public class PrivateSpaceCreationFragment extends InstrumentedFragment { } } else { mMetricsFeatureProvider.action( - getContext(), SettingsEnums.ACTION_PRIVATE_SPACE_SETUP_SPACE_CREATED, false); - showPrivateSpaceErrorScreen(); + getContext(), SettingsEnums.ACTION_PRIVATE_SPACE_SETUP_SPACE_CREATED, + false); + if (android.multiuser.Flags.showDifferentCreationErrorForUnsupportedDevices()) { + int errorCode = PrivateSpaceMaintainer.getInstance( + getActivity()).getPrivateSpaceCreateError(); + mMetricsFeatureProvider.action( + getContext(), SettingsEnums.ACTION_PRIVATE_SPACE_SETUP_SPACE_ERRORS, + errorCode); + showPrivateSpaceErrorScreen(errorCode); + } else { + showPrivateSpaceErrorScreen(); + } } } @@ -147,6 +164,16 @@ public class PrivateSpaceCreationFragment extends InstrumentedFragment { .navigate(R.id.action_create_profile_error); } + private void showPrivateSpaceErrorScreen(int errorCode) { + if (errorCode == UserManager.USER_OPERATION_ERROR_USER_RESTRICTED + || errorCode == UserManager.USER_OPERATION_ERROR_PRIVATE_PROFILE) { + NavHostFragment.findNavController(PrivateSpaceCreationFragment.this) + .navigate(R.id.action_create_profile_error_restrict); + } else { + showPrivateSpaceErrorScreen(); + } + } + /** Returns true if device has an active internet connection, false otherwise. */ private boolean isConnectedToInternet() { ConnectivityManager cm = diff --git a/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java b/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java index ec044daacbf..dd6a4bb6ab4 100644 --- a/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java +++ b/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java @@ -60,6 +60,7 @@ public class PrivateSpaceMaintainer { private final Context mContext; private final UserManager mUserManager; private final ActivityManager mActivityManager; + private int mErrorCode; @GuardedBy("this") private UserHandle mUserHandle; private final KeyguardManager mKeyguardManager; @@ -111,6 +112,9 @@ public class PrivateSpaceMaintainer { userName, USER_TYPE_PROFILE_PRIVATE, new ArraySet<>()); } catch (Exception e) { Log.e(TAG, "Error creating private space", e); + if (android.multiuser.Flags.showDifferentCreationErrorForUnsupportedDevices()) { + mErrorCode = ((UserManager.UserOperationException) e).getUserOperationResult(); + } return false; } @@ -312,6 +316,11 @@ public class PrivateSpaceMaintainer { return mUserManager.canAddPrivateProfile() || doesPrivateSpaceExist(); } + /** Returns the error code for private space creation failure*/ + public int getPrivateSpaceCreateError() { + return mErrorCode; + } + /** Returns true if private space exists and is running, otherwise returns false */ @VisibleForTesting synchronized boolean isPrivateProfileRunning() {