1 /*
2  * Copyright (C) 2023 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.devicelockcontroller.activities;
18 
19 import static com.android.devicelockcontroller.common.DeviceLockConstants.ACTION_START_DEVICE_FINANCING_PROVISIONING;
20 import static com.android.devicelockcontroller.common.DeviceLockConstants.ACTION_START_DEVICE_SUBSIDY_PROVISIONING;
21 
22 import static com.google.common.base.Preconditions.checkNotNull;
23 
24 import android.Manifest;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.pm.PackageManager;
28 import android.os.Bundle;
29 import android.text.TextUtils;
30 import android.view.LayoutInflater;
31 import android.view.View;
32 import android.view.ViewGroup;
33 import android.widget.Button;
34 import android.widget.ImageView;
35 import android.widget.TextView;
36 
37 import androidx.activity.result.ActivityResultLauncher;
38 import androidx.activity.result.contract.ActivityResultContracts;
39 import androidx.annotation.NonNull;
40 import androidx.annotation.Nullable;
41 import androidx.core.content.ContextCompat;
42 import androidx.fragment.app.Fragment;
43 import androidx.lifecycle.ViewModelProvider;
44 import androidx.recyclerview.widget.RecyclerView;
45 
46 import com.android.devicelockcontroller.R;
47 import com.android.devicelockcontroller.policy.PolicyObjectsProvider;
48 import com.android.devicelockcontroller.policy.ProvisionHelper;
49 import com.android.devicelockcontroller.policy.ProvisionHelperImpl;
50 import com.android.devicelockcontroller.util.LogUtil;
51 
52 import java.util.Objects;
53 
54 /**
55  * The screen that provides information about the provision.
56  */
57 public final class ProvisionInfoFragment extends Fragment {
58 
59     private static final String TAG = "ProvisionInfoFragment";
60     private ActivityResultLauncher<String> mResultLauncher;
61 
62     @Nullable
63     @Override
onCreateView( @onNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)64     public View onCreateView(
65             @NonNull LayoutInflater inflater,
66             @Nullable ViewGroup container,
67             @Nullable Bundle savedInstanceState) {
68         return inflater.inflate(R.layout.fragment_provision_info, container, false);
69     }
70 
71     @Override
onViewCreated(@onNull View view, @Nullable Bundle savedInstanceState)72     public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
73         super.onViewCreated(view, savedInstanceState);
74         ProvisionInfoViewModel viewModel;
75         ViewModelProvider viewModelProvider = new ViewModelProvider(this);
76         switch (Objects.requireNonNull(getActivity()).getIntent().getAction()) {
77             case ACTION_START_DEVICE_FINANCING_PROVISIONING:
78                 viewModel = viewModelProvider.get(DeviceFinancingProvisionInfoViewModel.class);
79                 break;
80             case ACTION_START_DEVICE_SUBSIDY_PROVISIONING:
81                 viewModel = viewModelProvider.get(DeviceSubsidyProvisionInfoViewModel.class);
82                 break;
83             default:
84                 LogUtil.e(TAG, "Unknown action is received, exiting");
85                 return;
86         }
87 
88         RecyclerView recyclerView = view.findViewById(R.id.recyclerview_provision_info);
89         if (recyclerView == null) {
90             LogUtil.e(TAG, "Could not find provision info RecyclerView, should not reach here.");
91             return;
92         }
93         ProvisionInfoListAdapter adapter = new ProvisionInfoListAdapter();
94         viewModel.mProvisionInfoListLiveData.observe(getViewLifecycleOwner(),
95                 adapter::submitList);
96         recyclerView.setAdapter(adapter);
97         ImageView imageView = view.findViewById(R.id.header_icon);
98         if (imageView == null) {
99             LogUtil.e(TAG, "Could not find header ImageView, should not reach here.");
100             return;
101         }
102         imageView.setImageResource(ProvisionInfoViewModel.HEADER_DRAWABLE_ID);
103 
104         TextView headerTextView = view.findViewById(R.id.header_text);
105         if (headerTextView == null) {
106             LogUtil.e(TAG, "Could not find header TextView, should not reach here.");
107             return;
108         }
109         viewModel.mHeaderTextLiveData.observe(getViewLifecycleOwner(),
110                 pair -> {
111                     if (pair.first > 0 && !TextUtils.isEmpty(pair.second)) {
112                         headerTextView.setText(getString(pair.first, pair.second));
113                     }
114                 });
115 
116         TextView subheaderTextView = view.findViewById(R.id.subheader_text);
117         if (subheaderTextView == null) {
118             LogUtil.e(TAG, "Could not find subheader TextView, should not reach here.");
119             return;
120         }
121         viewModel.mSubHeaderTextLiveData.observe(getViewLifecycleOwner(),
122                 pair -> {
123                     if (pair.first > 0 && !TextUtils.isEmpty(pair.second)) {
124                         subheaderTextView.setText(getString(pair.first, pair.second));
125                     }
126                 });
127         Button next = view.findViewById(R.id.button_next);
128         checkNotNull(next);
129         Context context = requireContext().getApplicationContext();
130         viewModel.mIsMandatoryLiveData.observe(this,
131                 isMandatory -> {
132                     if (!isMandatory) {
133                         next.setText(R.string.start);
134                         DeviceLockNotificationManager.getInstance()
135                                 .cancelDeferredProvisioningNotification(context);
136                     }
137                     next.setVisibility(View.VISIBLE);
138                 });
139         next.setOnClickListener(
140                 v -> startActivity(new Intent(context, ProvisioningActivity.class)));
141 
142         ProvisionHelper provisionHelper = new ProvisionHelperImpl(context,
143                 ((PolicyObjectsProvider) context).getProvisionStateController());
144         mResultLauncher = registerForActivityResult(new ActivityResultContracts.RequestPermission(),
145                 isGranted -> provisionHelper.pauseProvision());
146         updatePreviousButton(checkNotNull(view.findViewById(R.id.button_previous)), viewModel,
147                 provisionHelper);
148     }
149 
updatePreviousButton(Button previous, ProvisionInfoViewModel viewModel, ProvisionHelper provisionHelper)150     private void updatePreviousButton(Button previous, ProvisionInfoViewModel viewModel,
151             ProvisionHelper provisionHelper) {
152         viewModel.mIsMandatoryLiveData.observe(this,
153                 isMandatory -> {
154                     if (!isMandatory) {
155                         previous.setText(R.string.do_it_in_one_hour);
156                         previous.setVisibility(View.VISIBLE);
157                     }
158                 });
159 
160 
161         viewModel.mIsProvisionForcedLiveData.observe(getViewLifecycleOwner(),
162                 isProvisionForced -> {
163                     // Allow the user to defer provisioning only when provisioning is not forced.
164                     previous.setEnabled(!isProvisionForced);
165                     if (!isProvisionForced) {
166                         previous.setOnClickListener(
167                                 v -> {
168                                     int notificationPermission =
169                                             ContextCompat.checkSelfPermission(requireContext(),
170                                                     Manifest.permission.POST_NOTIFICATIONS);
171                                     if (PackageManager.PERMISSION_GRANTED
172                                             == notificationPermission) {
173                                         provisionHelper.pauseProvision();
174                                     } else {
175                                         mResultLauncher.launch(
176                                                 Manifest.permission.POST_NOTIFICATIONS);
177                                     }
178                                 });
179                     }
180                 });
181     }
182 }
183