diff --git a/res/layout/private_space_pre_finish_delay.xml b/res/layout/private_space_pre_finish_delay.xml new file mode 100644 index 00000000000..3b620bf256a --- /dev/null +++ b/res/layout/private_space_pre_finish_delay.xml @@ -0,0 +1,29 @@ + + + + + \ 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 80cd3997c4b..b027d87e556 100644 --- a/res/navigation/privatespace_main_context_nav.xml +++ b/res/navigation/privatespace_main_context_nav.xml @@ -46,6 +46,13 @@ android:id="@+id/action_retry_profile_creation" app:destination="@id/ps_auto_advance_fragment"/> + + + @@ -64,7 +71,7 @@ android:label="fragment_ps_lock"> + app:destination="@id/ps_pre_finish_delay_fragment"/> - + diff --git a/res/values/strings.xml b/res/values/strings.xml index f8c58ce937b..0e8b6045e5a 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1343,6 +1343,8 @@ Use screen lock Choose new lock + + Just a sec\u2026 All set! diff --git a/src/com/android/settings/privatespace/AutoAdvanceSetupFragment.java b/src/com/android/settings/privatespace/AutoAdvanceSetupFragment.java index 7f0118c5b92..d4e0046814e 100644 --- a/src/com/android/settings/privatespace/AutoAdvanceSetupFragment.java +++ b/src/com/android/settings/privatespace/AutoAdvanceSetupFragment.java @@ -59,7 +59,7 @@ public class AutoAdvanceSetupFragment extends InstrumentedFragment { private static final int ANIMATION_DURATION_MILLIS = 500; private static final int HEADER_TEXT_MAX_LINES = 4; private GlifLayout mRootView; - private Handler mHandler; + private static final Handler sHandler = new Handler(Looper.getMainLooper()); private int mScreenTitleIndex; private static final List> HEADER_ILLUSTRATION_PAIRS = ImmutableList.of( @@ -77,7 +77,7 @@ public class AutoAdvanceSetupFragment extends InstrumentedFragment { if (getActivity() != null) { if (++mScreenTitleIndex < HEADER_ILLUSTRATION_PAIRS.size()) { startFadeOutAnimation(); - mHandler.postDelayed(mUpdateScreenResources, DELAY_BETWEEN_SCREENS); + sHandler.postDelayed(mUpdateScreenResources, DELAY_BETWEEN_SCREENS); } else if (PrivateSpaceMaintainer.getInstance(getActivity()) .doesPrivateSpaceExist()) { mMetricsFeatureProvider.action( @@ -131,8 +131,6 @@ public class AutoAdvanceSetupFragment extends InstrumentedFragment { mRootView.getHeaderTextView().setMaxLines(HEADER_TEXT_MAX_LINES); mRootView.getHeaderTextView().setBreakStrategy(BREAK_STRATEGY_SIMPLE); updateHeaderAndIllustration(); - mHandler = new Handler(Looper.getMainLooper()); - mHandler.postDelayed(mUpdateScreenResources, DELAY_BETWEEN_SCREENS); OnBackPressedCallback callback = new OnBackPressedCallback(true /* enabled by default */) { @Override @@ -153,12 +151,16 @@ public class AutoAdvanceSetupFragment extends InstrumentedFragment { @Override public void onDestroy() { - if (mHandler != null) { - mHandler.removeCallbacks(mUpdateScreenResources); - } + 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; diff --git a/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java b/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java index 399c2c82fbb..11f4bcb74e3 100644 --- a/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java +++ b/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java @@ -97,7 +97,7 @@ public class PrivateSpaceSetLockFragment extends InstrumentedFragment { getContext(), SettingsEnums.ACTION_PRIVATE_SPACE_SETUP_USE_SCREEN_LOCK); // Simply Use default screen lock. No need to handle NavHostFragment.findNavController(PrivateSpaceSetLockFragment.this) - .navigate(R.id.action_lock_success_fragment); + .navigate(R.id.action_pre_finish_delay_fragment); }; } diff --git a/src/com/android/settings/privatespace/PrivateSpaceSetupActivity.java b/src/com/android/settings/privatespace/PrivateSpaceSetupActivity.java index ec7132adf0e..4cbcac74646 100644 --- a/src/com/android/settings/privatespace/PrivateSpaceSetupActivity.java +++ b/src/com/android/settings/privatespace/PrivateSpaceSetupActivity.java @@ -60,7 +60,7 @@ public class PrivateSpaceSetupActivity extends FragmentActivity { @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { if (requestCode == SET_LOCK_ACTION && resultCode == RESULT_OK) { - mNavHostFragment.getNavController().navigate(R.id.action_success_fragment); + mNavHostFragment.getNavController().navigate(R.id.action_pre_finish_delay_fragment); } else if (requestCode == ACCOUNT_LOGIN_ACTION) { if (resultCode == RESULT_OK) { mMetricsFeatureProvider.action( diff --git a/src/com/android/settings/privatespace/SetupPreFinishDelayFragment.java b/src/com/android/settings/privatespace/SetupPreFinishDelayFragment.java new file mode 100644 index 00000000000..aee8512ec9b --- /dev/null +++ b/src/com/android/settings/privatespace/SetupPreFinishDelayFragment.java @@ -0,0 +1,136 @@ +/* + * 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 static android.content.Intent.ACTION_PROFILE_INACCESSIBLE; +import static android.content.Intent.ACTION_PROFILE_UNAVAILABLE; + +import android.app.settings.SettingsEnums; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +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; + +public class SetupPreFinishDelayFragment extends InstrumentedFragment { + private static final String TAG = "SetupPreFinishDelayFrag"; + private static final Handler sHandler = new Handler(Looper.getMainLooper()); + private static final int MAX_DELAY_BEFORE_SETUP_FINISH = 5000; + private boolean mActionProfileUnavailable; + private boolean mActionProfileInaccessible; + + protected final BroadcastReceiver mBroadcastReceiver = + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent == null) { + return; + } + String action = intent.getAction(); + Log.i(TAG, "Received broadcast: " + action); + if (ACTION_PROFILE_UNAVAILABLE.equals(action)) { + mActionProfileUnavailable = true; + } else if (ACTION_PROFILE_INACCESSIBLE.equals(action)) { + mActionProfileInaccessible = true; + } + if (mActionProfileUnavailable && mActionProfileInaccessible) { + showSetupSuccessScreen(); + } + } + }; + + private Runnable mRunnable = + () -> { + showSetupSuccessScreen(); + }; + + @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_pre_finish_delay, 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); + if (savedInstanceState == null) { + // TODO(b/307729746): Add a test to verify PS is locked after setup completion. + PrivateSpaceMaintainer.getInstance(getActivity()).lockPrivateSpace(); + } + return rootView; + } + + @Override + public void onPause() { + super.onPause(); + getActivity().unregisterReceiver(mBroadcastReceiver); + } + + @Override + public void onResume() { + super.onResume(); + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(ACTION_PROFILE_UNAVAILABLE); + intentFilter.addAction(ACTION_PROFILE_INACCESSIBLE); + getActivity().registerReceiver(mBroadcastReceiver, intentFilter); + sHandler.postDelayed(mRunnable, MAX_DELAY_BEFORE_SETUP_FINISH); + } + + @Override + public int getMetricsCategory() { + return SettingsEnums.PRIVATE_SPACE_SETUP_PRE_FINISH; + } + + private void showSetupSuccessScreen() { + sHandler.removeCallbacks(mRunnable); + NavHostFragment.findNavController(SetupPreFinishDelayFragment.this) + .navigate(R.id.action_success_fragment); + } +} diff --git a/src/com/android/settings/privatespace/SetupSuccessFragment.java b/src/com/android/settings/privatespace/SetupSuccessFragment.java index cf63b22fead..65ac8f0e29f 100644 --- a/src/com/android/settings/privatespace/SetupSuccessFragment.java +++ b/src/com/android/settings/privatespace/SetupSuccessFragment.java @@ -86,8 +86,6 @@ public class SetupSuccessFragment extends InstrumentedFragment { if (activity != null) { mMetricsFeatureProvider.action( getContext(), SettingsEnums.ACTION_PRIVATE_SPACE_SETUP_DONE); - //TODO(b/307729746): Add a test to verify PS is locked after setup completion. - PrivateSpaceMaintainer.getInstance(activity).lockPrivateSpace(); Intent allAppsIntent = new Intent(Intent.ACTION_ALL_APPS); ResolveInfo resolveInfo = activity.getPackageManager()