diff --git a/AndroidManifest.xml b/AndroidManifest.xml index ffdc7e83217..9b9efe96195 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -4999,6 +4999,7 @@ + + + + + diff --git a/res/drawable/ic_warning_circle_red.xml b/res/drawable/ic_warning_circle_red.xml new file mode 100644 index 00000000000..4decf3aca80 --- /dev/null +++ b/res/drawable/ic_warning_circle_red.xml @@ -0,0 +1,20 @@ + + + + + diff --git a/res/drawable/privatespace_lock_placeholder.xml b/res/drawable/privatespace_lock_placeholder.xml new file mode 100644 index 00000000000..815ffd70d60 --- /dev/null +++ b/res/drawable/privatespace_lock_placeholder.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/drawable/privatespace_setup_flow_placeholder.xml b/res/drawable/privatespace_setup_flow_placeholder.xml new file mode 100644 index 00000000000..a4ff1252502 --- /dev/null +++ b/res/drawable/privatespace_setup_flow_placeholder.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/layout/privatespace_advancing_screen.xml b/res/layout/privatespace_advancing_screen.xml new file mode 100644 index 00000000000..cebb6fa1b63 --- /dev/null +++ b/res/layout/privatespace_advancing_screen.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + diff --git a/res/layout/privatespace_creation_error.xml b/res/layout/privatespace_creation_error.xml new file mode 100644 index 00000000000..af11f3ad8d7 --- /dev/null +++ b/res/layout/privatespace_creation_error.xml @@ -0,0 +1,27 @@ + + + + diff --git a/res/layout/privatespace_education_screen.xml b/res/layout/privatespace_education_screen.xml index e93ebfe06b2..adb65c982b6 100644 --- a/res/layout/privatespace_education_screen.xml +++ b/res/layout/privatespace_education_screen.xml @@ -15,12 +15,12 @@ --> diff --git a/res/layout/privatespace_setlock_screen.xml b/res/layout/privatespace_setlock_screen.xml new file mode 100644 index 00000000000..5caf4ae8b94 --- /dev/null +++ b/res/layout/privatespace_setlock_screen.xml @@ -0,0 +1,43 @@ + + + + + + + + + \ No newline at end of file diff --git a/res/layout/privatespace_setup_success.xml b/res/layout/privatespace_setup_success.xml new file mode 100644 index 00000000000..00b6fec2de8 --- /dev/null +++ b/res/layout/privatespace_setup_success.xml @@ -0,0 +1,27 @@ + + + + diff --git a/res/navigation/privatespace_main_context_nav.xml b/res/navigation/privatespace_main_context_nav.xml index f92e5720194..5b2552aece8 100644 --- a/res/navigation/privatespace_main_context_nav.xml +++ b/res/navigation/privatespace_main_context_nav.xml @@ -21,5 +21,29 @@ app:startDestination="@id/ps_education_fragment"> + android:label="fragment_ps_education"> + + + + + + + + + + \ No newline at end of file diff --git a/res/navigation/privatespace_private_context_nav.xml b/res/navigation/privatespace_private_context_nav.xml new file mode 100644 index 00000000000..3df8fa55b8c --- /dev/null +++ b/res/navigation/privatespace_private_context_nav.xml @@ -0,0 +1,24 @@ + + + + + diff --git a/res/values/dimens.xml b/res/values/dimens.xml index aa142170107..aed72dcd74d 100755 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -459,4 +459,7 @@ 42dp 3dp 1dp + + + 1000dp diff --git a/res/values/strings.xml b/res/values/strings.xml index f455ab52db1..942af44d8ca 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1239,24 +1239,54 @@ Set screen lock Cancel - + Cancel - + Set up - + Set up Private Space Hide private apps in a secure space that only you can access - + How it works You can access Private Space from the bottom of your apps list - + Apps in Private Space are protected by a lock - Notifications from apps in Private Space are hidden when it\'s locked + Notifications from apps in Private Space are hidden when it\u2019s locked - Private Space apps won\'t appear in permission manager, privacy dashboard, and other settings when Private Space is locked + Private Space apps won\u2019t appear in permission manager, privacy dashboard, and other settings when Private Space is locked + + Setting up Private Space\u2026 + + Private Space is protected by a lock + + Usage info for Private Space apps is hidden when it\u2019s locked + + Access Private Space from your apps list + + Couldn\u2019t set up Private Space + + Try again now, or come back later + + Try Again + + Use screen lock to unlock? + + You can unlock Private Space the same way you unlock your device, or choose a different lock + + Use screen lock + + Choose new lock + + All set! + + To access Private Space, swipe up from the bottom of your home screen, then scroll down + + Done + + Scroll down to access Private Space You can add up to %d fingerprints diff --git a/src/com/android/settings/privatespace/AutoAdvanceSetupFragment.java b/src/com/android/settings/privatespace/AutoAdvanceSetupFragment.java new file mode 100644 index 00000000000..5456c01a902 --- /dev/null +++ b/src/com/android/settings/privatespace/AutoAdvanceSetupFragment.java @@ -0,0 +1,150 @@ +/* + * 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 com.android.settings.privatespace.PrivateSpaceSetupActivity.SET_LOCK_ACTION; + +import android.annotation.SuppressLint; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.os.UserHandle; +import android.util.Log; +import android.util.Pair; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; + +import androidx.activity.OnBackPressedCallback; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.navigation.fragment.NavHostFragment; + +import com.android.settings.R; + +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 Fragment { + 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 GlifLayout mRootView; + private Handler mHandler; + private int mScreenTitleIndex; + private static final List> HEADER_IMAGE_PAIRS = + ImmutableList.of( + new Pair(R.string.privatespace_lock_protected_title, + R.drawable.privatespace_setup_flow_placeholder), + new Pair(R.string.privatespace_apps_hidden_title, + R.drawable.privatespace_setup_flow_placeholder), + new Pair(R.string.privatespace_access_from_apps_title, + R.drawable.privatespace_setup_flow_placeholder)); + + private Runnable mUpdateScreenResources = + new Runnable() { + @Override + public void run() { + if (getActivity() != null) { + if (++mScreenTitleIndex < HEADER_IMAGE_PAIRS.size()) { + updateHeaderAndImage(); + mHandler.postDelayed(mUpdateScreenResources, DELAY_BETWEEN_SCREENS); + } else { + PrivateSpaceMaintainer privateSpaceMaintainer = PrivateSpaceMaintainer + .getInstance(getActivity()); + UserHandle userHandle; + if (privateSpaceMaintainer.doesPrivateSpaceExist() && (userHandle = + privateSpaceMaintainer.getPrivateProfileHandle()) != null) { + startActivityInPrivateUser(userHandle); + } else { + showPrivateSpaceErrorScreen(); + } + } + } + } + }; + + @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_IMAGE_PAIRS.size()) { + return super.onCreateView(inflater, container, savedInstanceState); + } + } + mRootView = + (GlifLayout) + inflater.inflate(R.layout.privatespace_advancing_screen, container, false); + updateHeaderAndImage(); + mHandler = new Handler(Looper.getMainLooper()); + mHandler.postDelayed(mUpdateScreenResources, DELAY_BETWEEN_SCREENS); + 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() { + mHandler.removeCallbacks(mUpdateScreenResources); + super.onDestroy(); + } + + @SuppressLint("MissingPermission") + private void startActivityInPrivateUser(UserHandle userHandle) { + /* Start new activity in private profile which is needed to set private profile lock */ + Intent intent = new Intent(getContext(), PrivateProfileContextHelperActivity.class); + getActivity().startActivityForResultAsUser(intent, SET_LOCK_ACTION, userHandle); + } + + private void showPrivateSpaceErrorScreen() { + NavHostFragment.findNavController(AutoAdvanceSetupFragment.this) + .navigate(R.id.action_advance_profile_error); + } + + private void updateHeaderAndImage() { + mRootView.setHeaderText(HEADER_IMAGE_PAIRS.get(mScreenTitleIndex).first); + ((ImageView) mRootView.findViewById(R.id.placeholder_image)) + .setImageResource(HEADER_IMAGE_PAIRS.get(mScreenTitleIndex).second); + } +} diff --git a/src/com/android/settings/privatespace/PrivateProfileContextHelperActivity.java b/src/com/android/settings/privatespace/PrivateProfileContextHelperActivity.java new file mode 100644 index 00000000000..c0d762afaac --- /dev/null +++ b/src/com/android/settings/privatespace/PrivateProfileContextHelperActivity.java @@ -0,0 +1,42 @@ +/* + * 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 android.os.Bundle; + +import androidx.fragment.app.FragmentActivity; +import androidx.navigation.fragment.NavHostFragment; + +import com.android.settings.R; +import com.android.settings.SetupWizardUtils; + +import com.google.android.setupdesign.util.ThemeHelper; + +/** Activity that is started as private profile user that helps to set private profile lock. */ +public class PrivateProfileContextHelperActivity extends FragmentActivity { + private static final String TAG = "PrivateProfileHelper"; + @Override + protected void onCreate(Bundle savedInstanceState) { + setTheme(SetupWizardUtils.getTheme(this, getIntent())); + ThemeHelper.trySetDynamicColor(this); + super.onCreate(savedInstanceState); + setContentView(R.layout.privatespace_setup_root); + NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager() + .findFragmentById(R.id.ps_nav_host_fragment); + navHostFragment.getNavController().setGraph(R.navigation.privatespace_private_context_nav); + } +} diff --git a/src/com/android/settings/privatespace/PrivateProfileCreationError.java b/src/com/android/settings/privatespace/PrivateProfileCreationError.java new file mode 100644 index 00000000000..80826dd326d --- /dev/null +++ b/src/com/android/settings/privatespace/PrivateProfileCreationError.java @@ -0,0 +1,91 @@ +/* + * 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 android.app.Activity; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.activity.OnBackPressedCallback; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.navigation.fragment.NavHostFragment; + +import com.android.settings.R; + +import com.google.android.setupcompat.template.FooterBarMixin; +import com.google.android.setupcompat.template.FooterButton; +import com.google.android.setupdesign.GlifLayout; + +/** Fragment to display error screen if creation of private profile failed for any reason. */ +public class PrivateProfileCreationError extends Fragment { + @Override + public View onCreateView( + 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.privatespace_tryagain_label) + .setListener(onTryAgain()) + .setButtonType(FooterButton.ButtonType.NEXT) + .setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Primary) + .build()); + mixin.setSecondaryButton( + new FooterButton.Builder(getContext()) + .setText(R.string.privatespace_cancel_label) + .setListener(onCancel()) + .setButtonType(FooterButton.ButtonType.CANCEL) + .setTheme( + androidx.appcompat.R.style + .Base_TextAppearance_AppCompat_Widget_Button) + .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); + + return rootView; + } + + private View.OnClickListener onTryAgain() { + return v -> { + NavHostFragment.findNavController(PrivateProfileCreationError.this) + .navigate(R.id.action_retry_profile_creation); + }; + } + + private View.OnClickListener onCancel() { + return v -> { + Activity activity = getActivity(); + if (activity != null) { + activity.finish(); + } + }; + } +} diff --git a/src/com/android/settings/privatespace/PrivateSpaceEducation.java b/src/com/android/settings/privatespace/PrivateSpaceEducation.java index 96d0aa2e0c0..5dd0cfa4261 100644 --- a/src/com/android/settings/privatespace/PrivateSpaceEducation.java +++ b/src/com/android/settings/privatespace/PrivateSpaceEducation.java @@ -24,6 +24,7 @@ import android.view.ViewGroup; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; +import androidx.navigation.fragment.NavHostFragment; import com.android.settings.R; @@ -49,7 +50,6 @@ public class PrivateSpaceEducation extends Fragment { .setButtonType(FooterButton.ButtonType.NEXT) .setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Primary) .build()); - mixin.getPrimaryButtonView().setFilterTouchesWhenObscured(true); mixin.setSecondaryButton( new FooterButton.Builder(getContext()) .setText(R.string.privatespace_cancel_label) @@ -59,29 +59,24 @@ public class PrivateSpaceEducation extends Fragment { androidx.appcompat.R.style .Base_TextAppearance_AppCompat_Widget_Button) .build()); - mixin.getSecondaryButtonView().setFilterTouchesWhenObscured(true); return rootView; } private View.OnClickListener onSetup() { return v -> { - if (PrivateSpaceMaintainer.getInstance(getContext()).createPrivateSpace()) { - finishActivity(); - } + NavHostFragment.findNavController(PrivateSpaceEducation.this) + .navigate(R.id.action_education_to_auto_advance); + }; } private View.OnClickListener onCancel() { return v -> { - finishActivity(); + Activity activity = getActivity(); + if (activity != null) { + activity.finish(); + } }; } - - private void finishActivity() { - Activity activity = getActivity(); - if (activity != null) { - activity.finish(); - } - } } diff --git a/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java b/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java index af2da5bbe30..e6094ce3d10 100644 --- a/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java +++ b/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java @@ -162,6 +162,15 @@ public class PrivateSpaceMaintainer { /* title= */ null, /* description= */ null); } + /** Returns Private profile user handle if private profile exists otherwise returns null. */ + @Nullable + public synchronized UserHandle getPrivateProfileHandle() { + if (doesPrivateSpaceExist()) { + return mUserHandle; + } + return null; + } + /** Returns the instance of {@link PrivateSpaceMaintainer} */ public static synchronized PrivateSpaceMaintainer getInstance(Context context) { if (sPrivateSpaceMaintainer == null) { diff --git a/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java b/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java new file mode 100644 index 00000000000..3d176381c6b --- /dev/null +++ b/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java @@ -0,0 +1,125 @@ +/* + * 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.app.Activity.RESULT_OK; +import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD; +import static android.app.admin.DevicePolicyManager.EXTRA_PASSWORD_COMPLEXITY; +import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_LOW; + +import android.app.Activity; +import android.app.KeyguardManager; +import android.content.Intent; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.activity.OnBackPressedCallback; +import androidx.activity.result.ActivityResult; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; + +import com.android.settings.R; + +import com.google.android.setupcompat.template.FooterBarMixin; +import com.google.android.setupcompat.template.FooterButton; +import com.google.android.setupdesign.GlifLayout; + +/** Fragment that provides an option to user to choose between the existing screen lock or set a + * separate private profile lock. */ +public class PrivateSpaceSetLockFragment extends Fragment { + private final ActivityResultLauncher mVerifyDeviceLock = + registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), + this::onSetDeviceNewLock); + + @Override + public View onCreateView( + LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + GlifLayout rootView = + (GlifLayout) inflater.inflate( + R.layout.privatespace_setlock_screen, container, false); + final FooterBarMixin mixin = rootView.getMixin(FooterBarMixin.class); + mixin.setPrimaryButton( + new FooterButton.Builder(getContext()) + .setText(R.string.privatespace_use_screenlock_label) + .setListener(onClickUse()) + .setButtonType(FooterButton.ButtonType.NEXT) + .setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Primary) + .build()); + mixin.setSecondaryButton( + new FooterButton.Builder(getContext()) + .setText(R.string.privatespace_set_lock_label) + .setListener(onClickNewLock()) + .setButtonType(FooterButton.ButtonType.NEXT) + .setTheme( + androidx.appcompat.R.style + .Base_TextAppearance_AppCompat_Widget_Button) + .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); + + return rootView; + } + + private View.OnClickListener onClickUse() { + return v -> { + // Simply Use default screen lock. No need to handle + Activity activity = getActivity(); + if (activity != null) { + activity.setResult(RESULT_OK); + activity.finish(); + } + }; + } + + private View.OnClickListener onClickNewLock() { + return v -> { + createPrivateSpaceLock(); + }; + } + + private void createPrivateSpaceLock() { + final Intent intent = new Intent(ACTION_SET_NEW_PASSWORD); + intent.putExtra(EXTRA_PASSWORD_COMPLEXITY, PASSWORD_COMPLEXITY_LOW); + mVerifyDeviceLock.launch(intent); + } + + private void onSetDeviceNewLock(@Nullable ActivityResult result) { + // TODO(b/307281644) : Verify this for biometrics and check result code after new + // Authentication changes are merged. + if (result != null) { + Activity profileContextHelperActivity = getActivity(); + if (profileContextHelperActivity != null && profileContextHelperActivity + .getSystemService(KeyguardManager.class).isDeviceSecure()) { + profileContextHelperActivity.setResult(RESULT_OK); + profileContextHelperActivity.finish(); + } + } + } +} diff --git a/src/com/android/settings/privatespace/PrivateSpaceSetupActivity.java b/src/com/android/settings/privatespace/PrivateSpaceSetupActivity.java index 79e19fc5b9d..3a58e9eadeb 100644 --- a/src/com/android/settings/privatespace/PrivateSpaceSetupActivity.java +++ b/src/com/android/settings/privatespace/PrivateSpaceSetupActivity.java @@ -16,8 +16,10 @@ package com.android.settings.privatespace; +import android.content.Intent; import android.os.Bundle; +import androidx.annotation.Nullable; import androidx.fragment.app.FragmentActivity; import androidx.navigation.fragment.NavHostFragment; @@ -26,15 +28,26 @@ import com.android.settings.SetupWizardUtils; import com.google.android.setupdesign.util.ThemeHelper; +/** Activity class that helps in setting up of private space */ public class PrivateSpaceSetupActivity extends FragmentActivity { + public static final int SET_LOCK_ACTION = 1; + private NavHostFragment mNavHostFragment; @Override protected void onCreate(Bundle savedInstanceState) { setTheme(SetupWizardUtils.getTheme(this, getIntent())); ThemeHelper.trySetDynamicColor(this); super.onCreate(savedInstanceState); setContentView(R.layout.privatespace_setup_root); - NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager() + mNavHostFragment = (NavHostFragment) getSupportFragmentManager() .findFragmentById(R.id.ps_nav_host_fragment); - navHostFragment.getNavController().setGraph(R.navigation.privatespace_main_context_nav); + mNavHostFragment.getNavController().setGraph(R.navigation.privatespace_main_context_nav); + } + + @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_advance_to_success); + } + super.onActivityResult(requestCode, resultCode, data); } } diff --git a/src/com/android/settings/privatespace/SetupSuccessFragment.java b/src/com/android/settings/privatespace/SetupSuccessFragment.java new file mode 100644 index 00000000000..a8ca3f135ca --- /dev/null +++ b/src/com/android/settings/privatespace/SetupSuccessFragment.java @@ -0,0 +1,87 @@ +/* + * 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 android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Toast; + +import androidx.activity.OnBackPressedCallback; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; + +import com.android.settings.R; + +import com.google.android.setupcompat.template.FooterBarMixin; +import com.google.android.setupcompat.template.FooterButton; +import com.google.android.setupdesign.GlifLayout; + +/** Fragment for the final screen shown on successful completion of private space setup. */ +public class SetupSuccessFragment extends Fragment { + private static final String TAG = "SetupSuccessFragment"; + + @Override + public View onCreateView( + LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + GlifLayout rootView = + (GlifLayout) + inflater.inflate(R.layout.privatespace_setup_success, container, false); + final FooterBarMixin mixin = rootView.getMixin(FooterBarMixin.class); + mixin.setPrimaryButton( + new FooterButton.Builder(getContext()) + .setText(R.string.privatespace_done_label) + .setListener(onClickNext()) + .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); + + return rootView; + } + + private View.OnClickListener onClickNext() { + return v -> { + accessPrivateSpaceToast(); + // TODO: Replace with the intent to launch PS/PS Launch Settings + Intent startMain = new Intent(Intent.ACTION_MAIN); + startMain.addCategory(Intent.CATEGORY_HOME); + startActivity(startMain); + Activity activity = getActivity(); + if (activity != null) { + activity.finish(); + } + }; + } + + private void accessPrivateSpaceToast() { + Toast.makeText(getContext(), R.string.scrolldown_to_access, Toast.LENGTH_SHORT).show(); + } +}