diff --git a/res/layout/private_space_advancing_screen.xml b/res/layout/private_space_advancing_screen.xml deleted file mode 100644 index b3bb26c72f8..00000000000 --- a/res/layout/private_space_advancing_screen.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - diff --git a/res/layout/private_space_confirm_deletion.xml b/res/layout/private_space_confirm_deletion.xml index 31418e1d149..62940a3fe78 100644 --- a/res/layout/private_space_confirm_deletion.xml +++ b/res/layout/private_space_confirm_deletion.xml @@ -25,6 +25,6 @@ android:icon="@drawable/ic_delete_accent" app:sudUsePartnerHeavyTheme="true" app:sudIllustrationType="default" - app:sudDescriptionText = "@string/private_space_confirm_deletion_summary" + app:sudDescriptionText = "@string/private_space_few_moments_text" app:sucHeaderText="@string/private_space_confirm_deletion_header"> \ No newline at end of file diff --git a/res/layout/private_space_create_screen.xml b/res/layout/private_space_create_screen.xml new file mode 100644 index 00000000000..d98aba8ee58 --- /dev/null +++ b/res/layout/private_space_create_screen.xml @@ -0,0 +1,30 @@ + + + + + \ No newline at end of file diff --git a/res/navigation/privatespace_main_context_nav.xml b/res/navigation/privatespace_main_context_nav.xml index b027d87e556..0de5d9132ad 100644 --- a/res/navigation/privatespace_main_context_nav.xml +++ b/res/navigation/privatespace_main_context_nav.xml @@ -23,14 +23,14 @@ android:name="com.android.settings.privatespace.PrivateSpaceEducation" android:label="fragment_ps_education"> + android:id="@+id/action_education_to_create" + app:destination="@id/ps_create_fragment"/> - + + app:destination="@id/ps_create_fragment"/> Delete Deleting private space\u2026 - - This will take a few moments Private space deleted @@ -1332,14 +1330,10 @@ Learn more about private space https://support.google.com/android?p=private_space - + + This will take a few moments + Setting up private space\u2026 - - Notifications from private space apps are hidden when it\u2019s locked - - Explore private space settings to hide private space and set up automatic locking - - Required apps are already installed in your private space Couldn\u2019t set up a private space diff --git a/src/com/android/settings/privatespace/AutoAdvanceSetupFragment.java b/src/com/android/settings/privatespace/AutoAdvanceSetupFragment.java deleted file mode 100644 index 14627ecbf25..00000000000 --- a/src/com/android/settings/privatespace/AutoAdvanceSetupFragment.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (C) 2023 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 static android.text.Layout.BREAK_STRATEGY_SIMPLE; -import static android.view.View.ACCESSIBILITY_LIVE_REGION_POLITE; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; -import android.animation.ValueAnimator; -import android.app.settings.SettingsEnums; -import android.content.Context; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.util.Log; -import android.util.Pair; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import androidx.activity.OnBackPressedCallback; -import androidx.annotation.Nullable; -import androidx.navigation.fragment.NavHostFragment; - -import com.android.settings.R; -import com.android.settings.core.InstrumentedFragment; - -import com.airbnb.lottie.LottieAnimationView; -import com.google.android.setupdesign.GlifLayout; -import com.google.common.collect.ImmutableList; - -import org.jetbrains.annotations.NotNull; - -import java.util.List; - -/** Fragment to show screens that auto advance during private space setup flow */ -public class AutoAdvanceSetupFragment extends InstrumentedFragment { - private static final String TAG = "AutoAdvanceFragment"; - private static final String TITLE_INDEX = "title_index"; - private static final int DELAY_BETWEEN_SCREENS = 5000; // 5 seconds in millis - private static final int ANIMATION_DURATION_MILLIS = 500; - private static final int HEADER_TEXT_MAX_LINES = 4; - private GlifLayout mRootView; - private static final Handler sHandler = new Handler(Looper.getMainLooper()); - private int mScreenTitleIndex; - private static final List> HEADER_ILLUSTRATION_PAIRS = - ImmutableList.of( - new Pair(R.string.private_space_notifications_hidden_title, - R.raw.private_space_notifications_illustration), - new Pair(R.string.private_space_apps_installed_title, - R.raw.private_space_unlock_to_share_illustration), - new Pair(R.string.private_space_explore_settings_title, - R.raw.private_space_placeholder_illustration)); - - private Runnable mUpdateScreenResources = - new Runnable() { - @Override - public void run() { - if (getActivity() != null) { - if (++mScreenTitleIndex < HEADER_ILLUSTRATION_PAIRS.size()) { - startFadeOutAnimation(); - sHandler.postDelayed(mUpdateScreenResources, DELAY_BETWEEN_SCREENS); - } else if (PrivateSpaceMaintainer.getInstance(getActivity()) - .doesPrivateSpaceExist()) { - mMetricsFeatureProvider.action( - getContext(), - SettingsEnums.ACTION_PRIVATE_SPACE_SETUP_SPACE_CREATED, - true); - if (isConnectedToInternet()) { - NavHostFragment.findNavController(AutoAdvanceSetupFragment.this) - .navigate(R.id.action_account_intro_fragment); - } else { - NavHostFragment.findNavController(AutoAdvanceSetupFragment.this) - .navigate(R.id.action_set_lock_fragment); - } - } else { - mMetricsFeatureProvider.action( - getContext(), - SettingsEnums.ACTION_PRIVATE_SPACE_SETUP_SPACE_CREATED, - false); - showPrivateSpaceErrorScreen(); - } - } - } - }; - - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - if (android.os.Flags.allowPrivateProfile() - && android.multiuser.Flags.enablePrivateSpaceFeatures()) { - super.onCreate(savedInstanceState); - } - } - - @Override - public View onCreateView( - LayoutInflater inflater, - @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - if (savedInstanceState == null) { - if (PrivateSpaceMaintainer.getInstance(getActivity()).createPrivateSpace()) { - Log.i(TAG, "Private Space created"); - } - } else { - mScreenTitleIndex = savedInstanceState.getInt(TITLE_INDEX); - if (mScreenTitleIndex >= HEADER_ILLUSTRATION_PAIRS.size()) { - return super.onCreateView(inflater, container, savedInstanceState); - } - } - mRootView = - (GlifLayout) - inflater.inflate(R.layout.private_space_advancing_screen, container, false); - mRootView.getHeaderTextView().setMaxLines(HEADER_TEXT_MAX_LINES); - mRootView.getHeaderTextView().setBreakStrategy(BREAK_STRATEGY_SIMPLE); - mRootView.getHeaderTextView().setAccessibilityLiveRegion(ACCESSIBILITY_LIVE_REGION_POLITE); - updateHeaderAndIllustration(); - 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); - return mRootView; - } - - @Override - public void onSaveInstanceState(@NotNull Bundle outState) { - super.onSaveInstanceState(outState); - outState.putInt(TITLE_INDEX, mScreenTitleIndex); - } - - @Override - public void onDestroy() { - sHandler.removeCallbacks(mUpdateScreenResources); - super.onDestroy(); - } - - @Override - public void onResume() { - sHandler.postDelayed(mUpdateScreenResources, DELAY_BETWEEN_SCREENS); - super.onResume(); - } - - @Override - public int getMetricsCategory() { - return SettingsEnums.PRIVATE_SPACE_SETUP_SPACE_CREATION; - } - - private void showPrivateSpaceErrorScreen() { - NavHostFragment.findNavController(AutoAdvanceSetupFragment.this) - .navigate(R.id.action_advance_profile_error); - } - - private void updateHeaderAndIllustration() { - mRootView.setHeaderText(HEADER_ILLUSTRATION_PAIRS.get(mScreenTitleIndex).first); - LottieAnimationView animationView = mRootView.findViewById(R.id.lottie_animation); - animationView.setAnimation(HEADER_ILLUSTRATION_PAIRS.get(mScreenTitleIndex).second); - animationView.playAnimation(); - startFadeInAnimation(); - } - - private void startFadeInAnimation() { - ValueAnimator textView = ObjectAnimator.ofFloat( - mRootView.getHeaderTextView(), View.ALPHA, 0f, 1f); - ValueAnimator lottieView = ObjectAnimator.ofFloat( - mRootView.findViewById(R.id.lottie_animation), View.ALPHA, 0, 1f); - AnimatorSet fadeIn = new AnimatorSet(); - fadeIn.playTogether(textView, lottieView); - fadeIn.setDuration(ANIMATION_DURATION_MILLIS).start(); - } - - private void startFadeOutAnimation() { - AnimatorSet fadeOut = new AnimatorSet(); - ValueAnimator textView = ObjectAnimator.ofFloat( - mRootView.getHeaderTextView(), View.ALPHA, 1f, 0f); - ValueAnimator lottieView = ObjectAnimator.ofFloat( - mRootView.findViewById(R.id.lottie_animation), View.ALPHA, 1f, 0f); - fadeOut.playTogether(textView, lottieView); - fadeOut.setDuration(ANIMATION_DURATION_MILLIS).start(); - fadeOut.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - updateHeaderAndIllustration(); - } - }); - } - - /** Returns true if device has an active internet connection, false otherwise. */ - private boolean isConnectedToInternet() { - ConnectivityManager cm = - (ConnectivityManager) - getActivity().getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); - return activeNetwork != null && activeNetwork.isConnectedOrConnecting(); - } -} diff --git a/src/com/android/settings/privatespace/PrivateSpaceCreationFragment.java b/src/com/android/settings/privatespace/PrivateSpaceCreationFragment.java new file mode 100644 index 00000000000..1e0c65e0844 --- /dev/null +++ b/src/com/android/settings/privatespace/PrivateSpaceCreationFragment.java @@ -0,0 +1,130 @@ +/* + * 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.settings.SettingsEnums; +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.activity.OnBackPressedCallback; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.navigation.fragment.NavHostFragment; + +import com.android.settings.R; +import com.android.settings.core.InstrumentedFragment; + +import com.google.android.setupdesign.GlifLayout; + +/** Fragment to a show loading screen and create private profile during private space setup flow */ +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 Handler sHandler = new Handler(Looper.getMainLooper()); + private Runnable mRunnable = + () -> { + createPrivateSpace(); + }; + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + if (android.os.Flags.allowPrivateProfile() + && android.multiuser.Flags.enablePrivateSpaceFeatures()) { + super.onCreate(savedInstanceState); + } + } + + @NonNull + @Override + public View onCreateView( + @NonNull LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + GlifLayout rootView = + (GlifLayout) + inflater.inflate(R.layout.private_space_create_screen, container, false); + 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); + return rootView; + } + + @Override + public void onResume() { + super.onResume(); + // Ensures screen visibility to user by introducing a 1-second delay before creating private + // space. + sHandler.postDelayed(mRunnable, PRIVATE_SPACE_CREATE_POST_DELAY_MS); + } + + @Override + public void onDestroy() { + sHandler.removeCallbacks(mRunnable); + super.onDestroy(); + } + + private void createPrivateSpace() { + if (PrivateSpaceMaintainer.getInstance(getActivity()).createPrivateSpace()) { + Log.i(TAG, "Private Space created"); + mMetricsFeatureProvider.action( + getContext(), SettingsEnums.ACTION_PRIVATE_SPACE_SETUP_SPACE_CREATED, true); + if (isConnectedToInternet()) { + NavHostFragment.findNavController(PrivateSpaceCreationFragment.this) + .navigate(R.id.action_account_intro_fragment); + } else { + NavHostFragment.findNavController(PrivateSpaceCreationFragment.this) + .navigate(R.id.action_set_lock_fragment); + } + } else { + mMetricsFeatureProvider.action( + getContext(), SettingsEnums.ACTION_PRIVATE_SPACE_SETUP_SPACE_CREATED, false); + showPrivateSpaceErrorScreen(); + } + } + + @Override + public int getMetricsCategory() { + return SettingsEnums.PRIVATE_SPACE_SETUP_SPACE_CREATION; + } + + private void showPrivateSpaceErrorScreen() { + NavHostFragment.findNavController(PrivateSpaceCreationFragment.this) + .navigate(R.id.action_create_profile_error); + } + + /** Returns true if device has an active internet connection, false otherwise. */ + private boolean isConnectedToInternet() { + ConnectivityManager cm = + (ConnectivityManager) getActivity().getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); + return activeNetwork != null && activeNetwork.isConnectedOrConnecting(); + } +} diff --git a/src/com/android/settings/privatespace/PrivateSpaceEducation.java b/src/com/android/settings/privatespace/PrivateSpaceEducation.java index a21aac3c82d..f688b8d9374 100644 --- a/src/com/android/settings/privatespace/PrivateSpaceEducation.java +++ b/src/com/android/settings/privatespace/PrivateSpaceEducation.java @@ -91,7 +91,7 @@ public class PrivateSpaceEducation extends InstrumentedFragment { getContext(), SettingsEnums.ACTION_PRIVATE_SPACE_SETUP_START); Log.i(TAG, "Starting private space setup"); NavHostFragment.findNavController(PrivateSpaceEducation.this) - .navigate(R.id.action_education_to_auto_advance); + .navigate(R.id.action_education_to_create); }; } diff --git a/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java b/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java index 6a9ea9dcbca..999da5964bf 100644 --- a/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java +++ b/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java @@ -77,7 +77,7 @@ public class PrivateSpaceMaintainer { * *

This method should be used by the Private Space Setup Flow ONLY. */ - @VisibleForTesting + @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) public final synchronized boolean createPrivateSpace() { if (!Flags.allowPrivateProfile() || !android.multiuser.Flags.enablePrivateSpaceFeatures()) {