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() {