1 /*
2  * Copyright (C) 2022 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.car.settings.system;
18 
19 import android.Manifest;
20 import android.car.drivingstate.CarUxRestrictions;
21 import android.content.Context;
22 import android.content.pm.PackageManager;
23 import android.os.Bundle;
24 import android.os.PowerManager;
25 
26 import androidx.annotation.Nullable;
27 import androidx.annotation.VisibleForTesting;
28 import androidx.core.content.ContextCompat;
29 import androidx.preference.Preference;
30 
31 import com.android.car.settings.R;
32 import com.android.car.settings.common.ConfirmationDialogFragment;
33 import com.android.car.settings.common.FragmentController;
34 import com.android.car.settings.common.Logger;
35 import com.android.car.settings.common.PreferenceController;
36 
37 /**
38  * Controller which invokes the reboot service provided by PowerManager.
39  *
40  * @see PowerManager#reboot(String)
41  * @see PowerManager#isRebootingUserspaceSupported()
42  */
43 public class RestartSystemPreferenceController extends PreferenceController<Preference> {
44     private static final Logger LOG = new Logger(RestartSystemPreferenceController.class);
45     private static final String REBOOT_PERMISSIONS_TAG = Manifest.permission.REBOOT;
46     private final PowerManager mPowerManager;
47     private final boolean mIsRebootPermissionGranted;
48     @VisibleForTesting
49     final ConfirmationDialogFragment.ConfirmListener mRestartSystemConfirmListener;
50     @VisibleForTesting
51     final ConfirmationDialogFragment mDialogFragment;
52     @VisibleForTesting
53     static final String RESTART_SYSTEM_CONFIRM_DIALOG_TAG =
54             "com.android.car.settings.system.RestartSystemConfirmDialog";
55 
RestartSystemPreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions)56     public RestartSystemPreferenceController(Context context, String preferenceKey,
57             FragmentController fragmentController, CarUxRestrictions uxRestrictions) {
58         this(context, preferenceKey, fragmentController, uxRestrictions,
59                 /* isRebootPermissionGranted*/ (ContextCompat.checkSelfPermission(context,
60                         REBOOT_PERMISSIONS_TAG) == PackageManager.PERMISSION_GRANTED));
61     }
62 
63     @VisibleForTesting
RestartSystemPreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions, boolean isRebootPermissionGranted)64     RestartSystemPreferenceController(Context context, String preferenceKey,
65             FragmentController fragmentController, CarUxRestrictions uxRestrictions,
66             boolean isRebootPermissionGranted) {
67         super(context, preferenceKey, fragmentController, uxRestrictions);
68         mPowerManager = context.getSystemService(PowerManager.class);
69         mRestartSystemConfirmListener = getRestartSystemConfirmationListener();
70         mDialogFragment = getConfirmationDialogFragment();
71 
72         mIsRebootPermissionGranted = isRebootPermissionGranted;
73     }
74 
getRestartSystemConfirmationListener()75     private ConfirmationDialogFragment.ConfirmListener getRestartSystemConfirmationListener() {
76         return new ConfirmationDialogFragment.ConfirmListener() {
77             @Override
78             public void onConfirm(@Nullable Bundle arguments) {
79                 if (isRebootEnabled()) {
80                     LOG.d("Restarting infotainment system");
81                     mPowerManager.reboot(null);
82                 } else {
83                     LOG.e("Unable to access PowerManager system service or reboot permission is"
84                             + "not granted in the current package");
85                 }
86             }
87         };
88     }
89 
90     private ConfirmationDialogFragment getConfirmationDialogFragment() {
91         return new ConfirmationDialogFragment.Builder(getContext())
92                 .setMessage(R.string.restart_infotainment_system_dialog_text)
93                 .setPositiveButton(R.string.continue_confirmation,
94                         /* confirmListener= */ mRestartSystemConfirmListener)
95                 .setNegativeButton(android.R.string.cancel,
96                         /* rejectListener= */ null)
97                 .build();
98     }
99 
100     private boolean isRebootEnabled() {
101         return (mPowerManager != null) && mIsRebootPermissionGranted;
102     }
103 
104     @Override
105     protected boolean handlePreferenceClicked(Preference preference) {
106         getFragmentController().showDialog(mDialogFragment, RESTART_SYSTEM_CONFIRM_DIALOG_TAG);
107         return true;
108     }
109 
110     @Override
111     protected void onCreateInternal() {
112         ConfirmationDialogFragment.resetListeners(
113                 (ConfirmationDialogFragment) getFragmentController().findDialogByTag(
114                         RESTART_SYSTEM_CONFIRM_DIALOG_TAG),
115                 mRestartSystemConfirmListener,
116                 /* rejectListener= */ null,
117                 /* neutralListener= */ null);
118     }
119 
120     @Override
121     protected int getDefaultAvailabilityStatus() {
122         int availabilityStatus = super.getDefaultAvailabilityStatus();
123         if (availabilityStatus == AVAILABLE && !isRebootEnabled()) {
124             return UNSUPPORTED_ON_DEVICE;
125         }
126         return availabilityStatus;
127     }
128 
129     @Override
130     protected Class<Preference> getPreferenceType() {
131         return Preference.class;
132     }
133 
134 }
135