1 /* 2 * Copyright (C) 2021 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.applications; 18 19 import android.car.Car; 20 import android.car.drivingstate.CarUxRestrictions; 21 import android.car.watchdog.CarWatchdogManager; 22 import android.car.watchdog.PackageKillableState; 23 import android.content.Context; 24 import android.content.pm.PackageInfo; 25 import android.os.UserHandle; 26 27 import androidx.annotation.VisibleForTesting; 28 import androidx.preference.TwoStatePreference; 29 30 import com.android.car.settings.R; 31 import com.android.car.settings.common.ConfirmationDialogFragment; 32 import com.android.car.settings.common.FragmentController; 33 import com.android.car.settings.common.Logger; 34 import com.android.car.settings.common.PreferenceController; 35 import com.android.internal.annotations.GuardedBy; 36 37 import java.util.Objects; 38 39 /** Controller for preference which turns on / off prioritize app performance setting. */ 40 public class PrioritizeAppPerformancePreferenceController 41 extends PreferenceController<TwoStatePreference> { 42 private static final Logger LOG = 43 new Logger(PrioritizeAppPerformancePreferenceController.class); 44 45 @VisibleForTesting 46 static final String TURN_ON_PRIORITIZE_APP_PERFORMANCE_DIALOG_TAG = 47 "com.android.car.settings.applications.TurnOnPrioritizeAppPerformanceDialogTag"; 48 49 private final Object mLock = new Object(); 50 @GuardedBy("mLock") 51 private CarWatchdogManager mCarWatchdogManager; 52 53 private Car mCar; 54 private String mPackageName; 55 private UserHandle mUserHandle; 56 57 private final ConfirmationDialogFragment.ConfirmListener mConfirmListener = arguments -> { 58 setKillableState(false); 59 getPreference().setChecked(true); 60 }; 61 PrioritizeAppPerformancePreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions)62 public PrioritizeAppPerformancePreferenceController(Context context, String preferenceKey, 63 FragmentController fragmentController, 64 CarUxRestrictions uxRestrictions) { 65 super(context, preferenceKey, fragmentController, uxRestrictions); 66 } 67 68 @Override onCreateInternal()69 protected void onCreateInternal() { 70 if (mCar != null && mCar.isConnected()) { 71 mCar.disconnect(); 72 mCar = null; 73 } 74 mCar = Car.createCar(getContext(), null, Car.CAR_WAIT_TIMEOUT_WAIT_FOREVER, 75 (car, isReady) -> { 76 synchronized (mLock) { 77 mCarWatchdogManager = isReady 78 ? (CarWatchdogManager) car.getCarManager(Car.CAR_WATCHDOG_SERVICE) 79 : null; 80 } 81 }); 82 83 ConfirmationDialogFragment dialogFragment = 84 (ConfirmationDialogFragment) getFragmentController().findDialogByTag( 85 TURN_ON_PRIORITIZE_APP_PERFORMANCE_DIALOG_TAG); 86 ConfirmationDialogFragment.resetListeners( 87 dialogFragment, mConfirmListener, /* rejectListener= */ null, 88 /* neutralListener= */ null); 89 } 90 91 @Override onDestroyInternal()92 protected void onDestroyInternal() { 93 if (mCar != null) { 94 mCar.disconnect(); 95 mCar = null; 96 } 97 } 98 99 /** 100 * Set the package info of the application. 101 */ setPackageInfo(PackageInfo packageInfo)102 public void setPackageInfo(PackageInfo packageInfo) { 103 mPackageName = packageInfo.packageName; 104 mUserHandle = UserHandle.getUserHandleForUid(packageInfo.applicationInfo.uid); 105 } 106 107 @Override getPreferenceType()108 protected Class<TwoStatePreference> getPreferenceType() { 109 return TwoStatePreference.class; 110 } 111 112 @Override updateState(TwoStatePreference preference)113 protected void updateState(TwoStatePreference preference) { 114 int killableState = getKillableState(); 115 preference.setChecked(killableState == PackageKillableState.KILLABLE_STATE_NO); 116 preference.setEnabled(killableState != PackageKillableState.KILLABLE_STATE_NEVER); 117 } 118 119 @Override handlePreferenceChanged(TwoStatePreference preference, Object newValue)120 protected boolean handlePreferenceChanged(TwoStatePreference preference, Object newValue) { 121 boolean isToggledOn = (boolean) newValue; 122 if (isToggledOn) { 123 showConfirmationDialog(); 124 return false; 125 } 126 setKillableState(true); 127 return true; 128 } 129 getKillableState()130 private int getKillableState() { 131 synchronized (mLock) { 132 return Objects.requireNonNull(mCarWatchdogManager) 133 .getPackageKillableStatesAsUser(mUserHandle).stream() 134 .filter(pks -> pks.getPackageName().equals(mPackageName)) 135 .findFirst().map(PackageKillableState::getKillableState).orElse(-1); 136 } 137 } 138 setKillableState(boolean isKillable)139 private void setKillableState(boolean isKillable) { 140 synchronized (mLock) { 141 mCarWatchdogManager.setKillablePackageAsUser(mPackageName, mUserHandle, isKillable); 142 } 143 } 144 showConfirmationDialog()145 private void showConfirmationDialog() { 146 ConfirmationDialogFragment dialogFragment = 147 new ConfirmationDialogFragment.Builder(getContext()) 148 .setTitle(R.string.prioritize_app_performance_dialog_title) 149 .setMessage(R.string.prioritize_app_performance_dialog_text) 150 .setPositiveButton(R.string.prioritize_app_performance_dialog_action_on, 151 mConfirmListener) 152 .setNegativeButton(R.string.prioritize_app_performance_dialog_action_off, 153 /* rejectListener= */ null) 154 .build(); 155 getFragmentController().showDialog( 156 dialogFragment, TURN_ON_PRIORITIZE_APP_PERFORMANCE_DIALOG_TAG); 157 } 158 } 159