1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.privatespace;
18 
19 import static com.android.settings.privatespace.PrivateSpaceSetupActivity.ACCOUNT_LOGIN_ACTION;
20 import static com.android.settings.privatespace.PrivateSpaceSetupActivity.EXTRA_ACTION_TYPE;
21 
22 import android.app.settings.SettingsEnums;
23 import android.content.BroadcastReceiver;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.IntentFilter;
27 import android.net.ConnectivityManager;
28 import android.net.NetworkInfo;
29 import android.os.Bundle;
30 import android.os.Handler;
31 import android.os.Looper;
32 import android.util.Log;
33 import android.view.LayoutInflater;
34 import android.view.View;
35 import android.view.ViewGroup;
36 
37 import androidx.activity.OnBackPressedCallback;
38 import androidx.annotation.NonNull;
39 import androidx.annotation.Nullable;
40 import androidx.navigation.fragment.NavHostFragment;
41 
42 import com.android.settings.R;
43 import com.android.settings.core.InstrumentedFragment;
44 
45 import com.google.android.setupdesign.GlifLayout;
46 
47 /** Fragment to a show loading screen and create private profile during private space setup flow */
48 public class PrivateSpaceCreationFragment extends InstrumentedFragment {
49     private static final String TAG = "PrivateSpaceCreateFrag";
50     private static final int PRIVATE_SPACE_CREATE_POST_DELAY_MS = 1000;
51     private static final int PRIVATE_SPACE_ACCOUNT_LOGIN_POST_DELAY_MS = 5000;
52     private static final Handler sHandler = new Handler(Looper.getMainLooper());
53     private Runnable mRunnable =
54             () -> {
55                 createPrivateSpace();
56             };
57 
58     private Runnable mAccountLoginRunnable =
59             () -> {
60                 unRegisterReceiver();
61                 startAccountLogin();
62             };
63 
64     final BroadcastReceiver mProfileAccessReceiver = new  BroadcastReceiver() {
65         @Override
66         public void onReceive(Context context, Intent intent) {
67             final String action = intent.getAction();
68             if (action.equals(Intent.ACTION_PROFILE_ACCESSIBLE)) {
69                 Log.i(TAG, "onReceive " + action);
70                 sHandler.removeCallbacks(mAccountLoginRunnable);
71                 sHandler.post(mAccountLoginRunnable);
72             }
73         }
74     };
75 
76     @Override
onCreate(@ullable Bundle savedInstanceState)77     public void onCreate(@Nullable Bundle savedInstanceState) {
78         if (android.os.Flags.allowPrivateProfile()
79                 && android.multiuser.Flags.enablePrivateSpaceFeatures()) {
80             super.onCreate(savedInstanceState);
81         }
82     }
83 
84     @NonNull
85     @Override
onCreateView( @onNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)86     public View onCreateView(
87             @NonNull LayoutInflater inflater,
88             @Nullable ViewGroup container,
89             @Nullable Bundle savedInstanceState) {
90         GlifLayout rootView =
91                 (GlifLayout)
92                         inflater.inflate(R.layout.private_space_create_screen, container, false);
93         OnBackPressedCallback callback =
94                 new OnBackPressedCallback(true /* enabled by default */) {
95                     @Override
96                     public void handleOnBackPressed() {
97                         // Handle the back button event. We intentionally don't want to allow back
98                         // button to work in this screen during the setup flow.
99                     }
100                 };
101         requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);
102         return rootView;
103     }
104 
105     @Override
onResume()106     public void onResume() {
107         super.onResume();
108         // Ensures screen visibility to user by introducing a 1-second delay before creating private
109         // space.
110         sHandler.removeCallbacks(mRunnable);
111         sHandler.postDelayed(mRunnable, PRIVATE_SPACE_CREATE_POST_DELAY_MS);
112     }
113 
114     @Override
onDestroy()115     public void onDestroy() {
116         sHandler.removeCallbacks(mRunnable);
117         super.onDestroy();
118     }
119 
createPrivateSpace()120     private void createPrivateSpace() {
121         if (PrivateSpaceMaintainer.getInstance(getActivity()).createPrivateSpace()) {
122             Log.i(TAG, "Private Space created");
123             mMetricsFeatureProvider.action(
124                     getContext(), SettingsEnums.ACTION_PRIVATE_SPACE_SETUP_SPACE_CREATED, true);
125             if (isConnectedToInternet()) {
126                 registerReceiver();
127                 sHandler.postDelayed(
128                         mAccountLoginRunnable, PRIVATE_SPACE_ACCOUNT_LOGIN_POST_DELAY_MS);
129             } else {
130                 NavHostFragment.findNavController(PrivateSpaceCreationFragment.this)
131                         .navigate(R.id.action_set_lock_fragment);
132             }
133         } else {
134             mMetricsFeatureProvider.action(
135                     getContext(), SettingsEnums.ACTION_PRIVATE_SPACE_SETUP_SPACE_CREATED, false);
136             showPrivateSpaceErrorScreen();
137         }
138     }
139 
140     @Override
getMetricsCategory()141     public int getMetricsCategory() {
142         return SettingsEnums.PRIVATE_SPACE_SETUP_SPACE_CREATION;
143     }
144 
showPrivateSpaceErrorScreen()145     private void showPrivateSpaceErrorScreen() {
146         NavHostFragment.findNavController(PrivateSpaceCreationFragment.this)
147                 .navigate(R.id.action_create_profile_error);
148     }
149 
150     /** Returns true if device has an active internet connection, false otherwise. */
isConnectedToInternet()151     private boolean isConnectedToInternet() {
152         ConnectivityManager cm =
153                 (ConnectivityManager) getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
154         NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
155         return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
156     }
157 
158     /** Start new activity in private profile to add an account to private profile */
startAccountLogin()159     private void startAccountLogin() {
160         if (isAdded() && getContext() != null && getActivity() != null) {
161             Intent intent = new Intent(getContext(), PrivateProfileContextHelperActivity.class);
162             intent.putExtra(EXTRA_ACTION_TYPE, ACCOUNT_LOGIN_ACTION);
163             mMetricsFeatureProvider.action(
164                     getContext(), SettingsEnums.ACTION_PRIVATE_SPACE_SETUP_ACCOUNT_LOGIN_START);
165             getActivity().startActivityForResult(intent, ACCOUNT_LOGIN_ACTION);
166         }
167     }
168 
registerReceiver()169     private void registerReceiver() {
170         IntentFilter filter = new IntentFilter();
171         filter.addAction(Intent.ACTION_PROFILE_ACCESSIBLE);
172         if (getContext() != null) {
173             getContext().registerReceiver(mProfileAccessReceiver, filter);
174         }
175     }
176 
unRegisterReceiver()177     private void unRegisterReceiver() {
178         if (mProfileAccessReceiver != null && isAdded() && getContext() != null) {
179             getContext().unregisterReceiver(mProfileAccessReceiver);
180         }
181     }
182 }
183