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